From 35585c499f1466037b3788598756e1eb0009f51f Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Thu, 28 Feb 2019 22:43:53 +0000
Subject: [PATCH 01/24] Aggregation of drive-by cosmetic changes.

---
 src/libcore/cell.rs                           |   2 +-
 src/libcore/ops/unsize.rs                     |   2 +-
 src/librustc/hir/intravisit.rs                |   1 -
 src/librustc/hir/lowering.rs                  | 125 +++++++++---------
 src/librustc/hir/map/collector.rs             |   6 +-
 src/librustc/hir/map/definitions.rs           |   8 +-
 src/librustc/hir/map/mod.rs                   |  73 +++++-----
 src/librustc/hir/mod.rs                       |  36 +++--
 src/librustc/hir/print.rs                     |   4 +-
 src/librustc/ich/impls_hir.rs                 |   2 +-
 src/librustc/infer/mod.rs                     |   7 +-
 src/librustc/infer/opaque_types/mod.rs        |  25 ++--
 src/librustc/middle/resolve_lifetime.rs       |   4 +-
 src/librustc/middle/stability.rs              |   4 +-
 src/librustc/mir/interpret/error.rs           |   7 +-
 src/librustc/traits/error_reporting.rs        |   6 +-
 src/librustc/traits/select.rs                 |  28 ++--
 src/librustc/traits/structural_impls.rs       |   8 +-
 src/librustc/ty/context.rs                    |  14 +-
 src/librustc/ty/mod.rs                        |  24 ++--
 src/librustc/ty/query/plumbing.rs             |  22 +--
 src/librustc/ty/util.rs                       |   2 +-
 src/librustc/util/common.rs                   |  48 +++----
 src/librustc_borrowck/dataflow.rs             |  19 ++-
 src/librustc_codegen_llvm/intrinsic.rs        |   4 +-
 src/librustc_codegen_ssa/back/link.rs         |   8 +-
 src/librustc_codegen_ssa/mir/block.rs         |  22 +--
 src/librustc_codegen_ssa/mir/place.rs         |  45 ++++---
 src/librustc_lint/builtin.rs                  |  15 +--
 .../nll/region_infer/error_reporting/mod.rs   |   4 +-
 src/librustc_mir/build/mod.rs                 |   6 +-
 src/librustc_mir/monomorphize/partitioning.rs |  55 ++++----
 src/librustc_passes/ast_validation.rs         |  35 ++---
 src/librustc_resolve/lib.rs                   |  16 ++-
 src/librustc_typeck/astconv.rs                |  54 ++++----
 src/librustc_typeck/check/coercion.rs         |   2 +-
 src/librustc_typeck/check/mod.rs              |   8 +-
 src/librustc_typeck/check/writeback.rs        |  29 ++--
 src/librustc_typeck/collect.rs                |  51 +++----
 src/librustc_typeck/lib.rs                    |   8 +-
 src/librustdoc/clean/mod.rs                   |  20 +--
 src/librustdoc/html/format.rs                 |   7 +-
 src/libstd/panicking.rs                       |   5 +-
 src/libstd/sys_common/backtrace.rs            |   2 +-
 src/libsyntax/ast.rs                          |   4 +-
 src/libsyntax/ext/build.rs                    |  33 +++--
 src/libsyntax/parse/parser.rs                 |  58 ++++----
 src/libsyntax/print/pprust.rs                 |   8 +-
 src/libsyntax/ptr.rs                          |   3 +-
 src/libsyntax/visit.rs                        |   2 +-
 src/libsyntax_ext/deriving/generic/mod.rs     |   3 +-
 src/libsyntax_ext/proc_macro_decls.rs         |   7 +-
 .../pprust-expr-roundtrip.rs                  |  32 +++--
 .../traits/trait-object-auto-dedup.rs         |   9 +-
 .../no_revealing_outside_defining_module.rs   |   2 +-
 src/test/ui/type/type-alias-bounds.rs         |  36 ++---
 src/test/ui/type/type-alias-bounds.stderr     |  22 ++-
 57 files changed, 550 insertions(+), 542 deletions(-)

diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 9d26ecbacdcbb..239ff017cc230 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -1351,7 +1351,7 @@ impl<'b> BorrowRefMut<'b> {
         }
     }
 
-    // Clone a `BorrowRefMut`.
+    // Clones a `BorrowRefMut`.
     //
     // This is only valid if each `BorrowRefMut` is used to track a mutable
     // reference to a distinct, nonoverlapping range of the original object.
diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs
index 7f81481ab5b1d..8e46830084642 100644
--- a/src/libcore/ops/unsize.rs
+++ b/src/libcore/ops/unsize.rs
@@ -71,7 +71,7 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 
 /// This is used for object safety, to check that a method's receiver type can be dispatched on.
 ///
-/// example impl:
+/// An example implementation of the trait:
 ///
 /// ```
 /// # #![feature(dispatch_from_dyn, unsize)]
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 9cf365addca9b..f838ec84d8b31 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -934,7 +934,6 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
     visitor.visit_defaultness(defaultness);
 }
 
-
 pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
     if let Some(ctor_hir_id) = struct_definition.ctor_hir_id() {
         visitor.visit_id(ctor_hir_id);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 14a6e93341e32..af8c9c38de5ff 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -17,7 +17,7 @@
 //! 'folding' an existing one), then you create a new ID using `next_id()`.
 //!
 //! You must ensure that IDs are unique. That means that you should only use the
-//! ID from an AST node in a single HIR node (you can assume that AST node IDs
+//! ID from an AST node in a single HIR node (you can assume that AST node-IDs
 //! are unique). Every new node must have a unique ID. Avoid cloning HIR nodes.
 //! If you do, you must then set the new node's ID to a fresh one.
 //!
@@ -175,6 +175,8 @@ pub trait Resolver {
     ) -> hir::Path;
 }
 
+/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
+/// and if so, what meaning it has.
 #[derive(Debug)]
 enum ImplTraitContext<'a> {
     /// Treat `impl Trait` as shorthand for a new universal generic parameter.
@@ -670,14 +672,14 @@ impl<'a> LoweringContext<'a> {
 
     fn insert_item(&mut self, item: hir::Item) {
         let id = item.hir_id;
-        // FIXME: Use debug_asset-rt
+        // FIXME: Use `debug_asset-rt`.
         assert_eq!(id.local_id, hir::ItemLocalId::from_u32(0));
         self.items.insert(id, item);
         self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
     }
 
     fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
-        // Setup the counter if needed
+        // Set up the counter if needed.
         self.item_local_id_counters.entry(owner).or_insert(0);
         // Always allocate the first `HirId` for the owner itself.
         let lowered = self.lower_node_id_with_owner(owner, owner);
@@ -718,7 +720,7 @@ impl<'a> LoweringContext<'a> {
     {
         let counter = self.item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
-            .unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner));
+            .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
         let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
         self.current_hir_id_owner.push((def_index, counter));
         let ret = f(self);
@@ -758,7 +760,7 @@ impl<'a> LoweringContext<'a> {
             let local_id_counter = this
                 .item_local_id_counters
                 .get_mut(&owner)
-                .expect("called lower_node_id_with_owner before allocate_hir_id_counter");
+                .expect("called `lower_node_id_with_owner` before `allocate_hir_id_counter`");
             let local_id = *local_id_counter;
 
             // We want to be sure not to modify the counter in the map while it
@@ -771,7 +773,7 @@ impl<'a> LoweringContext<'a> {
                 .resolver
                 .definitions()
                 .opt_def_index(owner)
-                .expect("You forgot to call `create_def_with_parent` or are lowering node ids \
+                .expect("you forgot to call `create_def_with_parent` or are lowering node-IDs \
                          that do not belong to the current owner");
 
             hir::HirId {
@@ -863,7 +865,7 @@ impl<'a> LoweringContext<'a> {
         result
     }
 
-    /// Creates a new hir::GenericParam for every new lifetime and
+    /// Creates a new `hir::GenericParam` for every new lifetime and
     /// type parameter encountered while evaluating `f`. Definitions
     /// are created with the parent provided. If no `parent_id` is
     /// provided, no definitions will be returned.
@@ -1197,7 +1199,7 @@ impl<'a> LoweringContext<'a> {
         assert_eq!(
             len + 1,
             self.loop_scopes.len(),
-            "Loop scopes should be added and removed in stack order"
+            "loop scopes should be added and removed in stack order"
         );
 
         self.loop_scopes.pop().unwrap();
@@ -1351,9 +1353,9 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_generic_arg(&mut self,
-                        arg: &ast::GenericArg,
-                        itctx: ImplTraitContext<'_>)
-                        -> hir::GenericArg {
+                         arg: &ast::GenericArg,
+                         itctx: ImplTraitContext<'_>)
+                         -> hir::GenericArg {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
             ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
@@ -1537,7 +1539,7 @@ impl<'a> LoweringContext<'a> {
                     }
                 }
             }
-            TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
+            TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now."),
             TyKind::CVarArgs => {
                 // Create the implicit lifetime of the "spoofed" `VaList`.
                 let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
@@ -1563,7 +1565,7 @@ impl<'a> LoweringContext<'a> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
         // desugaring that explicitly states that we don't want to track that.
-        // Not tracking it makes lints in rustc and clippy very fragile as
+        // Not tracking it makes lints in rustc and clippy very fragile, as
         // frequently opened issues show.
         let exist_ty_span = self.mark_span_with_reason(
             CompilerDesugaringKind::ExistentialReturnType,
@@ -1650,7 +1652,7 @@ impl<'a> LoweringContext<'a> {
         parent_index: DefIndex,
         bounds: &hir::GenericBounds,
     ) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
-        // This visitor walks over impl trait bounds and creates defs for all lifetimes which
+        // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
         // appear in the bounds, excluding lifetimes that are created within the bounds.
         // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
         struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
@@ -1758,8 +1760,7 @@ impl<'a> LoweringContext<'a> {
                         def_node_id,
                         DefPathData::LifetimeNs(name.ident().as_interned_str()),
                         Mark::root(),
-                        lifetime.span,
-                    );
+                        lifetime.span);
 
                     let (name, kind) = match name {
                         hir::LifetimeName::Underscore => (
@@ -1770,7 +1771,7 @@ impl<'a> LoweringContext<'a> {
                             param_name,
                             hir::LifetimeParamKind::Explicit,
                         ),
-                        _ => bug!("expected LifetimeName::Param or ParamName::Plain"),
+                        _ => bug!("expected `LifetimeName::Param` or `ParamName::Plain`"),
                     };
 
                     self.output_lifetime_params.push(hir::GenericParam {
@@ -1915,7 +1916,7 @@ impl<'a> LoweringContext<'a> {
                         {
                             ParenthesizedGenericArgs::Err
                         }
-                        // A warning for now, for compatibility reasons
+                        // A warning for now, for compatibility reasons.
                         _ => ParenthesizedGenericArgs::Warn,
                     };
 
@@ -2079,11 +2080,14 @@ impl<'a> LoweringContext<'a> {
                             }
                         };
                         err.emit();
-                        (self.lower_angle_bracketed_parameter_data(
-                            &data.as_angle_bracketed_args(),
-                            param_mode,
-                            itctx).0,
-                         false)
+                        (
+                            self.lower_angle_bracketed_parameter_data(
+                                &data.as_angle_bracketed_args(),
+                                param_mode,
+                                itctx
+                            ).0,
+                            false,
+                        )
                     }
                 },
             }
@@ -2109,11 +2113,11 @@ impl<'a> LoweringContext<'a> {
                 let no_ty_args = generic_args.args.len() == expected_lifetimes;
                 let no_bindings = generic_args.bindings.is_empty();
                 let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
-                    // If there are no (non-implicit) generic args or associated-type
+                    // If there are no (non-implicit) generic args or associated type
                     // bindings, our suggestion includes the angle brackets.
                     (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
                 } else {
-                    // Otherwise—sorry, this is kind of gross—we need to infer the
+                    // Otherwise (sorry, this is kind of gross) we need to infer the
                     // place to splice in the `'_, ` from the generics that do exist.
                     let first_generic_span = first_generic_span
                         .expect("already checked that type args or bindings exist");
@@ -2196,19 +2200,21 @@ impl<'a> LoweringContext<'a> {
             ast::GenericArg::Type(_) => true,
             _ => false,
         });
-        (hir::GenericArgs {
-            args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
-            bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
-            parenthesized: false,
-        },
-        !has_types && param_mode == ParamMode::Optional)
+        (
+            hir::GenericArgs {
+                args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
+                bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
+                parenthesized: false,
+            },
+            !has_types && param_mode == ParamMode::Optional
+        )
     }
 
     fn lower_parenthesized_parameter_data(
         &mut self,
         data: &ParenthesizedArgs,
     ) -> (hir::GenericArgs, bool) {
-        // Switch to `PassThrough` mode for anonymous lifetimes: this
+        // Switch to `PassThrough` mode for anonymous lifetimes; this
         // means that we permit things like `&Ref<T>`, where `Ref` has
         // a hidden lifetime parameter. This is needed for backwards
         // compatibility, even in contexts like an impl header where
@@ -2300,16 +2306,16 @@ impl<'a> LoweringContext<'a> {
 
     // Lowers a function declaration.
     //
-    // decl: the unlowered (ast) function declaration.
-    // fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
+    // `decl`: the unlowered (AST) function declaration.
+    // `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
     //      given DefId, otherwise impl Trait is disallowed. Must be `Some` if
-    //      make_ret_async is also `Some`.
-    // impl_trait_return_allow: determines whether impl Trait can be used in return position.
-    //      This guards against trait declarations and implementations where impl Trait is
+    //      `make_ret_async` is also `Some`.
+    // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
+    //      This guards against trait declarations and implementations where `impl Trait` is
     //      disallowed.
-    // make_ret_async: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
-    //      return type. This is used for `async fn` declarations. The `NodeId` is the id of the
-    //      return type impl Trait item.
+    // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
+    //      return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
+    //      return type `impl Trait` item.
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
@@ -2350,7 +2356,7 @@ impl<'a> LoweringContext<'a> {
             );
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
+                in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
                 ret_id,
                 lt_replacement,
             )
@@ -2401,16 +2407,16 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    // Transform `-> T` for `async fn` into -> ExistTy { .. }
+    // Transforms `-> T` for `async fn` into `-> ExistTy { .. }`
     // combined with the following definition of `ExistTy`:
     //
-    // existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
+    //     existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
     //
-    // inputs: lowered types of arguments to the function. Used to collect lifetimes.
-    // output: unlowered output type (`T` in `-> T`)
-    // fn_def_id: DefId of the parent function. Used to create child impl trait definition.
-    // exist_ty_node_id: NodeId of the existential type that should be created.
-    // elided_lt_replacement: replacement for elided lifetimes in the return type
+    // `inputs`: lowered types of arguments to the function (used to collect lifetimes)
+    // `output`: unlowered output type (`T` in `-> T`)
+    // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
+    // `exist_ty_node_id`: `NodeId` of the existential type that should be created
+    // `elided_lt_replacement`: replacement for elided lifetimes in the return type
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FunctionRetTy,
@@ -2511,7 +2517,7 @@ impl<'a> LoweringContext<'a> {
         }))
     }
 
-    /// Turns `-> T` into `Future<Output = T>`
+    /// Transforms `-> T` into `Future<Output = T>`
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
         output: &FunctionRetTy,
@@ -2757,9 +2763,9 @@ impl<'a> LoweringContext<'a> {
         -> hir::Generics
     {
         // Collect `?Trait` bounds in where clause and move them to parameter definitions.
-        // FIXME: this could probably be done with less rightward drift. Also looks like two control
-        //        paths where report_error is called are also the only paths that advance to after
-        //        the match statement, so the error reporting could probably just be moved there.
+        // FIXME: this could probably be done with less rightward drift. It also looks like two
+        // control paths where `report_error` is called are the only paths that advance to after the
+        // match statement, so the error reporting could probably just be moved there.
         let mut add_bounds: NodeMap<Vec<_>> = Default::default();
         for pred in &generics.where_clause.predicates {
             if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
@@ -2952,7 +2958,7 @@ impl<'a> LoweringContext<'a> {
             hir_id: self.lower_node_id(f.id),
             ident: match f.ident {
                 Some(ident) => ident,
-                // FIXME(jseyfried): positional field hygiene
+                // FIXME(jseyfried): positional field hygiene.
                 None => Ident::new(sym::integer(index), f.span),
             },
             vis: self.lower_visibility(&f.vis, None),
@@ -2979,7 +2985,7 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_param_bounds(&mut self, bounds: &[GenericBound], mut itctx: ImplTraitContext<'_>)
-        -> hir::GenericBounds {
+                          -> hir::GenericBounds {
         bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
     }
 
@@ -3157,7 +3163,7 @@ impl<'a> LoweringContext<'a> {
         match *i {
             ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name),
             ItemKind::Use(ref use_tree) => {
-                // Start with an empty prefix
+                // Start with an empty prefix.
                 let prefix = Path {
                     segments: vec![],
                     span: use_tree.span,
@@ -3345,7 +3351,8 @@ impl<'a> LoweringContext<'a> {
                 self.lower_generics(generics, ImplTraitContext::disallowed()),
                 self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
             ),
-            ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
+            ItemKind::MacroDef(..)
+            | ItemKind::Mac(..) => bug!("`TyMac` should have been expanded by now"),
         }
 
         // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
@@ -3632,7 +3639,7 @@ impl<'a> LoweringContext<'a> {
                         .map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
                 ),
             ),
-            TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
+            TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
         };
 
         hir::TraitItem {
@@ -3707,7 +3714,7 @@ impl<'a> LoweringContext<'a> {
                     self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
                 ),
             ),
-            ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
+            ImplItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
         };
 
         hir::ImplItem {
@@ -5347,7 +5354,7 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    /// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+    /// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when
     /// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
     /// The path is also resolved according to `is_value`.
     fn std_path(
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index b5203f9ec1f72..e66fa13f4fca2 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -19,7 +19,7 @@ use std::iter::repeat;
 use crate::ich::StableHashingContext;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
 
-/// A Visitor that walks over the HIR and collects Nodes into a HIR map
+/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
 pub(super) struct NodeCollector<'a, 'hir> {
     /// The crate
     krate: &'hir Crate,
@@ -45,7 +45,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
 
     hcx: StableHashingContext<'a>,
 
-    // We are collecting DepNode::HirBody hashes here so we can compute the
+    // We are collecting `DepNode::HirBody` hashes here so we can compute the
     // crate hash from then later on.
     hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
 }
@@ -109,7 +109,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
 
         let mut hir_body_nodes = Vec::new();
 
-        // Allocate DepNodes for the root module
+        // Allocate `DepNode`s for the root module.
         let (root_mod_sig_dep_index, root_mod_full_dep_index) = {
             let Crate {
                 ref module,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 2324c3f04284f..b85f6f6ce8483 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -239,7 +239,7 @@ impl DefPath {
                        "{}[{}]",
                        component.data.as_interned_str(),
                        component.disambiguator)
-                    .unwrap();
+                       .unwrap();
             }
         }
 
@@ -263,7 +263,7 @@ impl DefPath {
                        "{}[{}]",
                        component.data.as_interned_str(),
                        component.disambiguator)
-                    .unwrap();
+                       .unwrap();
             }
         }
         s
@@ -442,7 +442,7 @@ impl Definitions {
         root_index
     }
 
-    /// Add a definition with a parent definition.
+    /// Adds a definition with a parent definition.
     pub fn create_def_with_parent(&mut self,
                                   parent: DefIndex,
                                   node_id: ast::NodeId,
@@ -559,7 +559,7 @@ impl DefPathData {
             GlobalMetaData(name) => {
                 return name
             }
-            // note that this does not show up in user printouts
+            // Note that this does not show up in user print-outs.
             CrateRoot => sym::double_braced_crate,
             Impl => sym::double_braced_impl,
             Misc => sym::double_braced_misc,
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 75799a1903174..18c596f164dc2 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -1,7 +1,8 @@
 use self::collector::NodeCollector;
 pub use self::def_collector::{DefCollector, MacroInvocationData};
-pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
-                            DisambiguatedDefPathData, DefPathHash};
+pub use self::definitions::{
+    Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, DefPathHash
+};
 
 use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex};
 
@@ -238,7 +239,7 @@ impl<'hir> Map<'hir> {
         })
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     #[inline]
     pub fn local_def_id_from_hir_id(&self, hir_id: HirId) -> DefId {
         self.opt_local_def_id_from_hir_id(hir_id).unwrap_or_else(|| {
@@ -247,7 +248,7 @@ impl<'hir> Map<'hir> {
         })
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     #[inline]
     pub fn opt_local_def_id_from_hir_id(&self, hir_id: HirId) -> Option<DefId> {
         let node_id = self.hir_to_node_id(hir_id);
@@ -264,7 +265,7 @@ impl<'hir> Map<'hir> {
         self.definitions.as_local_node_id(def_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     #[inline]
     pub fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> {
         self.definitions.as_local_hir_id(def_id)
@@ -426,7 +427,7 @@ impl<'hir> Map<'hir> {
         self.fn_decl_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<FnDecl> {
         if let Some(entry) = self.find_entry(hir_id) {
             entry.fn_decl().cloned()
@@ -455,7 +456,7 @@ impl<'hir> Map<'hir> {
         self.maybe_body_owned_by_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn maybe_body_owned_by_by_hir_id(&self, hir_id: HirId) -> Option<BodyId> {
         if let Some(entry) = self.find_entry(hir_id) {
             if self.dep_graph.is_fully_enabled() {
@@ -483,7 +484,7 @@ impl<'hir> Map<'hir> {
         self.body_owner_kind_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn body_owner_kind_by_hir_id(&self, id: HirId) -> BodyOwnerKind {
         match self.get_by_hir_id(id) {
             Node::Item(&Item { node: ItemKind::Const(..), .. }) |
@@ -587,14 +588,13 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Retrieve the Node corresponding to `id`, panicking if it cannot
-    /// be found.
+    /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
     pub fn get(&self, id: NodeId) -> Node<'hir> {
         let hir_id = self.node_to_hir_id(id);
         self.get_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_by_hir_id(&self, id: HirId) -> Node<'hir> {
         // read recorded by `find`
         self.find_by_hir_id(id).unwrap_or_else(||
@@ -634,7 +634,7 @@ impl<'hir> Map<'hir> {
         self.find_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn find_by_hir_id(&self, hir_id: HirId) -> Option<Node<'hir>> {
         let result = self.find_entry(hir_id).and_then(|entry| {
             if let Node::Crate = entry.node {
@@ -665,7 +665,7 @@ impl<'hir> Map<'hir> {
         self.hir_to_node_id(parent_hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_parent_node_by_hir_id(&self, hir_id: HirId) -> HirId {
         if self.dep_graph.is_fully_enabled() {
             let hir_id_owner = hir_id.owner;
@@ -721,24 +721,24 @@ impl<'hir> Map<'hir> {
     {
         let mut id = start_id;
         loop {
-            let parent_node = self.get_parent_node_by_hir_id(id);
-            if parent_node == CRATE_HIR_ID {
+            let parent_id = self.get_parent_node_by_hir_id(id);
+            if parent_id == CRATE_HIR_ID {
                 return Ok(CRATE_HIR_ID);
             }
-            if parent_node == id {
+            if parent_id == id {
                 return Err(id);
             }
 
-            if let Some(entry) = self.find_entry(parent_node) {
+            if let Some(entry) = self.find_entry(parent_id) {
                 if let Node::Crate = entry.node {
                     return Err(id);
                 }
                 if found(&entry.node) {
-                    return Ok(parent_node);
+                    return Ok(parent_id);
                 } else if bail_early(&entry.node) {
-                    return Err(parent_node);
+                    return Err(parent_id);
                 }
-                id = parent_node;
+                id = parent_id;
             } else {
                 return Err(id);
             }
@@ -803,7 +803,7 @@ impl<'hir> Map<'hir> {
         self.hir_to_node_id(parent_hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
         match self.walk_parent_nodes(hir_id, |node| match *node {
             Node::Item(_) |
@@ -824,7 +824,7 @@ impl<'hir> Map<'hir> {
         self.get_module_parent_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_module_parent_by_hir_id(&self, id: HirId) -> DefId {
         self.local_def_id_from_hir_id(self.get_module_parent_node(id))
     }
@@ -861,7 +861,7 @@ impl<'hir> Map<'hir> {
         self.get_parent_did_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_parent_did_by_hir_id(&self, id: HirId) -> DefId {
         self.local_def_id_from_hir_id(self.get_parent_item(id))
     }
@@ -871,7 +871,7 @@ impl<'hir> Map<'hir> {
         self.get_foreign_abi_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn get_foreign_abi_by_hir_id(&self, hir_id: HirId) -> Abi {
         let parent = self.get_parent_item(hir_id);
         if let Some(entry) = self.find_entry(parent) {
@@ -890,7 +890,7 @@ impl<'hir> Map<'hir> {
         self.expect_item_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn expect_item_by_hir_id(&self, id: HirId) -> &'hir Item {
         match self.find_by_hir_id(id) { // read recorded by `find`
             Some(Node::Item(item)) => item,
@@ -946,7 +946,7 @@ impl<'hir> Map<'hir> {
         self.expect_expr_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn expect_expr_by_hir_id(&self, id: HirId) -> &'hir Expr {
         match self.find_by_hir_id(id) { // read recorded by find
             Some(Node::Expr(expr)) => expr,
@@ -960,7 +960,7 @@ impl<'hir> Map<'hir> {
         self.name_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn name_by_hir_id(&self, id: HirId) -> Name {
         match self.get_by_hir_id(id) {
             Node::Item(i) => i.ident.name,
@@ -977,14 +977,14 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Given a node ID, get a list of attributes associated with the AST
-    /// corresponding to the Node ID
+    /// Given a node ID, gets a list of attributes associated with the AST
+    /// corresponding to the node-ID.
     pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] {
         let hir_id = self.node_to_hir_id(id);
         self.attrs_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn attrs_by_hir_id(&self, id: HirId) -> &'hir [ast::Attribute] {
         self.read(id); // reveals attributes on the node
         let attrs = match self.find_entry(id).map(|entry| entry.node) {
@@ -1053,7 +1053,7 @@ impl<'hir> Map<'hir> {
         self.span_by_hir_id(hir_id)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn span_by_hir_id(&self, hir_id: HirId) -> Span {
         self.read(hir_id); // reveals span from node
         match self.find_entry(hir_id).map(|entry| entry.node) {
@@ -1101,7 +1101,7 @@ impl<'hir> Map<'hir> {
         hir_id_to_string(self, self.node_to_hir_id(id), true)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn hir_to_string(&self, id: HirId) -> String {
         hir_id_to_string(self, id, true)
     }
@@ -1110,7 +1110,7 @@ impl<'hir> Map<'hir> {
         hir_id_to_string(self, self.node_to_hir_id(id), false)
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn hir_to_user_string(&self, id: HirId) -> String {
         hir_id_to_string(self, id, false)
     }
@@ -1119,7 +1119,7 @@ impl<'hir> Map<'hir> {
         print::to_string(self, |s| s.print_node(self.get(id)))
     }
 
-    // FIXME(@ljedrz): replace the NodeId variant
+    // FIXME(@ljedrz): replace the `NodeId` variant.
     pub fn hir_to_pretty_string(&self, id: HirId) -> String {
         print::to_string(self, |s| s.print_node(self.get_by_hir_id(id)))
     }
@@ -1451,8 +1451,9 @@ pub fn provide(providers: &mut Providers<'_>) {
         if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
             tcx.hir().def_kind(node_id)
         } else {
-            bug!("Calling local def_kind query provider for upstream DefId: {:?}",
-                def_id)
+            bug!("calling local def_kind query provider for upstream DefId: {:?}",
+                def_id
+            );
         }
     };
 }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 65fc56f2c4878..e29998db7778f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1,4 +1,4 @@
-// HIR datatypes. See the [rustc guide] for more info.
+//! HIR datatypes. See the [rustc guide] for more info.
 //!
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html
 
@@ -121,13 +121,13 @@ impl fmt::Display for HirId {
     }
 }
 
-// hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
+// Hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
 mod item_local_id_inner {
     use rustc_data_structures::indexed_vec::Idx;
     use rustc_macros::HashStable;
     newtype_index! {
-        /// An `ItemLocalId` uniquely identifies something within a given "item-like",
-        /// that is, within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
+        /// An `ItemLocalId` uniquely identifies something within a given "item-like";
+        /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
         /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
         /// the node's position within the owning item in any way, but there is a
         /// guarantee that the `LocalItemId`s within an owner occupy a dense range of
@@ -568,7 +568,6 @@ pub struct GenericParam {
     pub bounds: GenericBounds,
     pub span: Span,
     pub pure_wrt_drop: bool,
-
     pub kind: GenericParamKind,
 }
 
@@ -1566,13 +1565,13 @@ pub enum ExprKind {
 
     /// A struct or struct-like variant literal expression.
     ///
-    /// For example, `Foo {x: 1, y: 2}`, or
-    /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
+    /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
+    /// where `base` is the `Option<Expr>`.
     Struct(P<QPath>, HirVec<Field>, Option<P<Expr>>),
 
     /// An array literal constructed from one repeated element.
     ///
-    /// For example, `[1; 5]`. The first expression is the element
+    /// E.g., `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
     Repeat(P<Expr>, AnonConst),
 
@@ -1583,7 +1582,7 @@ pub enum ExprKind {
     Err,
 }
 
-/// Optionally `Self`-qualified value/type path or associated extension.
+/// Represents an optionally `Self`-qualified value/type path or associated extension.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum QPath {
     /// Path to a definition, optionally "fully-qualified" with a `Self`
@@ -1738,7 +1737,7 @@ pub struct TraitItem {
     pub span: Span,
 }
 
-/// A trait method's body (or just argument names).
+/// Represents a trait method's body (or just argument names).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum TraitMethod {
     /// No default body in the trait, just a signature.
@@ -1751,13 +1750,12 @@ pub enum TraitMethod {
 /// Represents a trait method or associated constant or type
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum TraitItemKind {
-    /// An associated constant with an optional value (otherwise `impl`s
-    /// must contain a value)
+    /// An associated constant with an optional value (otherwise `impl`s must contain a value).
     Const(P<Ty>, Option<BodyId>),
-    /// A method with an optional body
+    /// A method with an optional body.
     Method(MethodSig, TraitMethod),
     /// An associated type with (possibly empty) bounds and optional concrete
-    /// type
+    /// type.
     Type(GenericBounds, Option<P<Ty>>),
 }
 
@@ -1808,9 +1806,9 @@ pub struct TypeBinding {
 
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Ty {
+    pub hir_id: HirId,
     pub node: TyKind,
     pub span: Span,
-    pub hir_id: HirId,
 }
 
 impl fmt::Debug for Ty {
@@ -1874,7 +1872,7 @@ pub enum TyKind {
     BareFn(P<BareFnTy>),
     /// The never type (`!`).
     Never,
-    /// A tuple (`(A, B, C, D,...)`).
+    /// A tuple (`(A, B, C, D, ...)`).
     Tup(HirVec<Ty>),
     /// A path to a type definition (`module::module::...::Type`), or an
     /// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
@@ -2598,7 +2596,7 @@ impl CodegenFnAttrs {
         }
     }
 
-    /// True if it looks like this symbol needs to be exported, for example:
+    /// Returns `true` if it looks like this symbol needs to be exported, for example:
     ///
     /// * `#[no_mangle]` is present
     /// * `#[export_name(...)]` is present
@@ -2607,8 +2605,8 @@ impl CodegenFnAttrs {
         self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) ||
             self.export_name.is_some() ||
             match self.linkage {
-                // these are private, make sure we don't try to consider
-                // them external
+                // These are private, so make sure we don't try to consider
+                // them external.
                 None |
                 Some(Linkage::Internal) |
                 Some(Linkage::Private) => false,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index c5337381a3d4f..709a43c4734c1 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1679,8 +1679,8 @@ impl<'a> State<'a> {
                 })?;
             }
 
-            // FIXME(eddyb) This would leak into error messages, e.g.:
-            // "non-exhaustive patterns: `Some::<..>(_)` not covered".
+            // FIXME(eddyb): this would leak into error messages (e.g.,
+            // "non-exhaustive patterns: `Some::<..>(_)` not covered").
             if infer_types && false {
                 start_or_comma(self)?;
                 self.s.word("..")?;
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 5b2a1e783c039..f2f909b6af156 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -286,7 +286,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
 
         inner_span.hash_stable(hcx, hasher);
 
-        // Combining the DefPathHashes directly is faster than feeding them
+        // Combining the `DefPathHash`s directly is faster than feeding them
         // into the hasher. Because we use a commutative combine, we also don't
         // have to sort the array.
         let item_ids_hash = item_ids
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 4414e677fb5b7..e9c47002278df 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -914,10 +914,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // variable, and because type variable's can't (at present, at
         // least) capture any of the things bound by this binder.
         //
-        // Really, there is no *particular* reason to do this
-        // `shallow_resolve` here except as a
-        // micro-optimization. Naturally I could not
-        // resist. -nmatsakis
+        // NOTE(nmatsakis): really, there is no *particular* reason to do this
+        // `shallow_resolve` here except as a micro-optimization.
+        // Naturally I could not resist.
         let two_unbound_type_vars = {
             let a = self.shallow_resolve(predicate.skip_binder().a);
             let b = self.shallow_resolve(predicate.skip_binder().b);
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 220b7b5fa67fe..1423b855745e7 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -858,7 +858,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
             def_id, substs
         );
 
-        // Use the same type variable if the exact same Opaque appears more
+        // Use the same type variable if the exact same opaque type appears more
         // than once in the return type (e.g., if it's passed to a type alias).
         if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
             return opaque_defn.concrete_ty;
@@ -880,9 +880,9 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
             required_region_bounds
         );
 
-        // make sure that we are in fact defining the *entire* type
-        // e.g., `existential type Foo<T: Bound>: Bar;` needs to be
-        // defined by a function like `fn foo<T: Bound>() -> Foo<T>`.
+        // Make sure that we are in fact defining the *entire* type
+        // (e.g., `existential type Foo<T: Bound>: Bar;` needs to be
+        // defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
         debug!(
             "instantiate_opaque_types: param_env: {:#?}",
             self.param_env,
@@ -945,18 +945,15 @@ pub fn may_define_existential_type(
     def_id: DefId,
     opaque_hir_id: hir::HirId,
 ) -> bool {
-    let mut hir_id = tcx
-        .hir()
-        .as_local_hir_id(def_id)
-        .unwrap();
-    // named existential types can be defined by any siblings or
-    // children of siblings
+    let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    // Named existential types can be defined by any siblings or
+    // children of siblings.
     let mod_id = tcx.hir().get_parent_item(opaque_hir_id);
-    // so we walk up the node tree until we hit the root or the parent
-    // of the opaque type
-    while hir_id != mod_id && hir_id != hir::CRATE_HIR_ID {
+    // We walk up the node tree until we hit the root or the parent
+    // of the opaque type.
+    while hir_id != mod_id && node_id != ast::CRATE_HIR_ID {
         hir_id = tcx.hir().get_parent_item(hir_id);
     }
-    // syntactically we are allowed to define the concrete type
+    // Syntactically we are allowed to define the concrete type.
     hir_id == mod_id
 }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 7c57c50595bc8..2e56ca6f56352 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1,6 +1,6 @@
 //! Name resolution for lifetimes.
 //!
-//! Name resolution for lifetimes follows MUCH simpler rules than the
+//! Name resolution for lifetimes follows *much* simpler rules than the
 //! full resolve. For example, lifetime names are never exported or
 //! used between functions, and they operate in a purely top-down
 //! way. Therefore, we break lifetime name resolution into a separate pass.
@@ -1009,7 +1009,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         trait_ref: &'tcx hir::PolyTraitRef,
         _modifier: hir::TraitBoundModifier,
     ) {
-        debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
+        debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
         if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| {
             match param.kind {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index b81a4538d971d..815c68b6b1cb6 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -124,12 +124,12 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
             // This crate explicitly wants staged API.
             debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
             if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
-                self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \
+                self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged API; \
                                                  use `#[rustc_deprecated]` instead");
             }
             if let Some(mut stab) = attr::find_stability(&self.tcx.sess.parse_sess,
                                                          attrs, item_sp) {
-                // Error if prohibited, or can't inherit anything from a container
+                // Error if prohibited, or can't inherit anything from a container.
                 if kind == AnnotationKind::Prohibited ||
                    (kind == AnnotationKind::Container &&
                     stab.level.is_stable() &&
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index ac7c07c366d51..b4615aeb0db15 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -49,7 +49,8 @@ pub struct ConstEvalErr<'tcx> {
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct FrameInfo<'tcx> {
-    pub call_site: Span, // this span is in the caller!
+    /// This span is in the caller.
+    pub call_site: Span,
     pub instance: ty::Instance<'tcx>,
     pub lint_root: Option<hir::HirId>,
 }
@@ -200,12 +201,12 @@ fn print_backtrace(backtrace: &mut Backtrace) {
 impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> {
     fn from(kind: InterpError<'tcx, u64>) -> Self {
         let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
-            // matching RUST_BACKTRACE, we treat "0" the same as "not present".
+            // Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
             Ok(ref val) if val != "0" => {
                 let mut backtrace = Backtrace::new_unresolved();
 
                 if val == "immediate" {
-                    // Print it now
+                    // Print it now.
                     print_backtrace(&mut backtrace);
                     None
                 } else {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 95312d55b3be1..9f22e6a108891 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -662,7 +662,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             "{}",
                             message.unwrap_or_else(||
                                 format!("the trait bound `{}` is not satisfied{}",
-                                         trait_ref.to_predicate(), post_message)
+                                        trait_ref.to_predicate(), post_message)
                             ));
 
                         let explanation =
@@ -676,7 +676,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             };
 
                         if let Some(ref s) = label {
-                            // If it has a custom "#[rustc_on_unimplemented]"
+                            // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s.as_str());
                             err.help(&explanation);
@@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             err.span_label(span, explanation);
                         }
                         if let Some(ref s) = note {
-                            // If it has a custom "#[rustc_on_unimplemented]" note, let's display it
+                            // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
                             err.note(s.as_str());
                         }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index ba96233b85328..fc9756d52f55d 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1465,9 +1465,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let predicate = self.infcx()
             .resolve_vars_if_possible(&obligation.predicate);
 
-        // OK to skip binder because of the nature of the
+        // Okay to skip binder because of the nature of the
         // trait-ref-is-knowable check, which does not care about
-        // bound regions
+        // bound regions.
         let trait_ref = predicate.skip_binder().trait_ref;
 
         let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref);
@@ -1853,7 +1853,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let matching_bounds =
             all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
 
-        // keep only those bounds which may apply, and propagate overflow if it occurs
+        // Keep only those bounds which may apply, and propagate overflow if it occurs.
         let mut param_candidates = vec![];
         for bound in matching_bounds {
             let wc = self.evaluate_where_clause(stack, bound.clone())?;
@@ -1891,9 +1891,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return Ok(());
         }
 
-        // OK to skip binder because the substs on generator types never
+        // Okay to skip binder because the substs on generator types never
         // touch bound regions, they just capture the in-scope
-        // type/region parameters
+        // type/region parameters.
         let self_ty = *obligation.self_ty().skip_binder();
         match self_ty.sty {
             ty::Generator(..) => {
@@ -1935,7 +1935,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
         };
 
-        // OK to skip binder because the substs on closure types never
+        // Okay to skip binder because the substs on closure types never
         // touch bound regions, they just capture the in-scope
         // type/region parameters
         match obligation.self_ty().skip_binder().sty {
@@ -1985,7 +1985,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return Ok(());
         }
 
-        // OK to skip binder because what we are inspecting doesn't involve bound regions
+        // Okay to skip binder because what we are inspecting doesn't involve bound regions
         let self_ty = *obligation.self_ty().skip_binder();
         match self_ty.sty {
             ty::Infer(ty::TyVar(_)) => {
@@ -2042,7 +2042,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        // OK to skip binder here because the tests we do below do not involve bound regions
+        // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = *obligation.self_ty().skip_binder();
         debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
 
@@ -2274,7 +2274,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        // OK to skip binder here because the tests we do below do not involve bound regions
+        // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = *obligation.self_ty().skip_binder();
         debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
 
@@ -3094,7 +3094,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         debug!("confirm_fn_pointer_candidate({:?})", obligation);
 
-        // OK to skip binder; it is reintroduced below
+        // Okay to skip binder; it is reintroduced below.
         let self_ty = self.infcx
             .shallow_resolve(*obligation.self_ty().skip_binder());
         let sig = self_ty.fn_sig(self.tcx());
@@ -3172,9 +3172,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        // OK to skip binder because the substs on generator types never
+        // Okay to skip binder because the substs on generator types never
         // touch bound regions, they just capture the in-scope
-        // type/region parameters
+        // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let (generator_def_id, substs) = match self_ty.sty {
             ty::Generator(id, substs, _) => (id, substs),
@@ -3229,9 +3229,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             .fn_trait_kind(obligation.predicate.def_id())
             .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
 
-        // OK to skip binder because the substs on closure types never
+        // Okay to skip binder because the substs on closure types never
         // touch bound regions, they just capture the in-scope
-        // type/region parameters
+        // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let (closure_def_id, substs) = match self_ty.sty {
             ty::Closure(id, substs) => (id, substs),
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 404fadbc78afc..4d382d6c45a76 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -10,11 +10,11 @@ use std::fmt;
 use std::rc::Rc;
 use std::collections::{BTreeSet, BTreeMap};
 
-// structural impls for the structs in traits
+// Structural impls for the structs in `traits`.
 
 impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "Normalized({:?},{:?})", self.value, self.obligations)
+        write!(f, "Normalized({:?}, {:?})", self.value, self.obligations)
     }
 }
 
@@ -23,13 +23,13 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
         if ty::tls::with(|tcx| tcx.sess.verbose()) {
             write!(
                 f,
-                "Obligation(predicate={:?},cause={:?},param_env={:?},depth={})",
+                "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})",
                 self.predicate, self.cause, self.param_env, self.recursion_depth
             )
         } else {
             write!(
                 f,
-                "Obligation(predicate={:?},depth={})",
+                "Obligation(predicate={:?}, depth={})",
                 self.predicate, self.recursion_depth
             )
         }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2599b8fbf6ff1..e60022033cc54 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1706,21 +1706,21 @@ impl<'gcx> GlobalCtxt<'gcx> {
     }
 }
 
-/// A trait implemented for all X<'a> types which can be safely and
-/// efficiently converted to X<'tcx> as long as they are part of the
-/// provided TyCtxt<'tcx>.
-/// This can be done, for example, for Ty<'tcx> or SubstsRef<'tcx>
+/// A trait implemented for all `X<'a>` types that can be safely and
+/// efficiently converted to `X<'tcx>` as long as they are part of the
+/// provided `TyCtxt<'tcx>`.
+/// This can be done, for example, for `Ty<'tcx>` or `SubstsRef<'tcx>`
 /// by looking them up in their respective interners.
 ///
 /// However, this is still not the best implementation as it does
 /// need to compare the components, even for interned values.
-/// It would be more efficient if TypedArena provided a way to
+/// It would be more efficient if `TypedArena` provided a way to
 /// determine whether the address is in the allocated range.
 ///
 /// None is returned if the value or one of the components is not part
 /// of the provided context.
-/// For Ty, None can be returned if either the type interner doesn't
-/// contain the TyKind key or if the address of the interned
+/// For `Ty`, `None` can be returned if either the type interner doesn't
+/// contain the `TyKind` key or if the address of the interned
 /// pointer differs. The latter case is possible if a primitive type,
 /// e.g., `()` or `u8`, was interned in a different context.
 pub trait Lift<'tcx>: fmt::Debug {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index e585f9939a014..69bf05c66f394 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1090,7 +1090,7 @@ pub enum Predicate<'tcx> {
     /// See the `ProjectionPredicate` struct for details.
     Projection(PolyProjectionPredicate<'tcx>),
 
-    /// no syntax: `T` well-formed
+    /// No syntax: `T` well-formed.
     WellFormed(Ty<'tcx>),
 
     /// Trait must be object-safe.
@@ -1245,19 +1245,17 @@ impl<'tcx> TraitPredicate<'tcx> {
 
 impl<'tcx> PolyTraitPredicate<'tcx> {
     pub fn def_id(&self) -> DefId {
-        // ok to skip binder since trait def-id does not care about regions
+        // Ok to skip binder since trait def-ID does not care about regions.
         self.skip_binder().def_id()
     }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
          Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A: B`
-pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
-pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
-                                                           ty::Region<'tcx>>;
-pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>,
-                                                         ty::Region<'tcx>>;
+pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
+pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>;
+pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
+pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
 pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
 pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>;
 
@@ -1314,7 +1312,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
     /// Note that this is not the `DefId` of the `TraitRef` containing this
     /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
     pub fn projection_def_id(&self) -> DefId {
-        // okay to skip binder since trait def-id does not care about regions
+        // Ok to skip binder since trait def-ID does not care about regions.
         self.skip_binder().projection_ty.item_def_id
     }
 }
@@ -1371,7 +1369,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     }
 }
 
-// A custom iterator used by Predicate::walk_tys.
+// A custom iterator used by `Predicate::walk_tys`.
 enum WalkTysIter<'tcx, I, J, K>
     where I: Iterator<Item = Ty<'tcx>>,
           J: Iterator<Item = Ty<'tcx>>,
@@ -1505,7 +1503,7 @@ impl<'tcx> Predicate<'tcx> {
 ///
 /// Example:
 ///
-///     struct Foo<T,U:Bar<T>> { ... }
+///     struct Foo<T, U: Bar<T>> { ... }
 ///
 /// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like
 /// `[[], [U:Bar<T>]]`. Now if there were some particular reference
@@ -2785,10 +2783,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 e.span
             }
             Some(f) => {
-                bug!("Node id {} is not an expr: {:?}", id, f);
+                bug!("node-ID {} is not an expr: {:?}", id, f);
             }
             None => {
-                bug!("Node id {} is not present in the node map", id);
+                bug!("node-ID {} is not present in the node map", id);
             }
         }
     }
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index d671b58470c6a..c2760ccb0c0a2 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -96,12 +96,12 @@ pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> {
 }
 
 impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
-    /// Either gets a JobOwner corresponding the query, allowing us to
+    /// Either gets a `JobOwner` corresponding the query, allowing us to
     /// start executing the query, or it returns with the result of the query.
     /// If the query is executing elsewhere, this will wait for it.
     /// If the query panicked, this will silently panic.
     ///
-    /// This function is inlined because that results in a noticeable speedup
+    /// This function is inlined because that results in a noticeable speed-up
     /// for some compile-time benchmarks.
     #[inline(always)]
     pub(super) fn try_get(
@@ -126,9 +126,9 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
                 Entry::Occupied(entry) => {
                     match *entry.get() {
                         QueryResult::Started(ref job) => {
-                            //For parallel queries, we'll block and wait until the query running
-                            //in another thread has completed. Record how long we wait in the
-                            //self-profiler
+                            // For parallel queries, we'll block and wait until the query running
+                            // in another thread has completed. Record how long we wait in the
+                            // self-profiler.
                             #[cfg(parallel_compiler)]
                             tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME));
 
@@ -138,7 +138,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
                     }
                 }
                 Entry::Vacant(entry) => {
-                    // No job entry for this query. Return a new one to be started later
+                    // No job entry for this query. Return a new one to be started later.
                     return tls::with_related_context(tcx, |icx| {
                         // Create the `parent` variable before `info`. This allows LLVM
                         // to elide the move of `info`
@@ -161,14 +161,14 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
             mem::drop(lock);
 
             // If we are single-threaded we know that we have cycle error,
-            // so we just return the error
+            // so we just return the error.
             #[cfg(not(parallel_compiler))]
             return TryGetJob::Cycle(cold_path(|| {
                 Q::handle_cycle_error(tcx, job.find_cycle_in_stack(tcx, span))
             }));
 
             // With parallel queries we might just have to wait on some other
-            // thread
+            // thread.
             #[cfg(parallel_compiler)]
             {
                 let result = job.r#await(tcx, span);
@@ -636,8 +636,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                           profq_query_msg!(Q::NAME.as_str(), self, key))
         );
 
-        // We may be concurrently trying both execute and force a query
-        // Ensure that only one of them runs the query
+        // We may be concurrently trying both execute and force a query.
+        // Ensure that only one of them runs the query.
         let job = match JobOwner::try_get(self, span, &key) {
             TryGetJob::NotYetStarted(job) => job,
             TryGetJob::Cycle(_) |
@@ -731,7 +731,7 @@ macro_rules! define_queries_inner {
                 let mut jobs = Vec::new();
 
                 // We use try_lock here since we are only called from the
-                // deadlock handler, and this shouldn't be locked
+                // deadlock handler, and this shouldn't be locked.
                 $(
                     jobs.extend(
                         self.$name.try_lock().unwrap().active.values().filter_map(|v|
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 926c0f8b94919..9b4029f409ba4 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -546,7 +546,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor
     }
 
-    /// Given the `DefId` of a fn or closure, returns the `DefId` of
+    /// Given the def-ID of a fn or closure, returns the def-ID of
     /// the innermost fn item that the closure is contained within.
     /// This is a significant `DefId` because, when we do
     /// type-checking, we type-check this fn item and all of its
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 67eaa19c080b5..2140018223c34 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -18,7 +18,7 @@ use crate::dep_graph::{DepNode};
 use lazy_static;
 use crate::session::Session;
 
-// The name of the associated type for `Fn` return types
+// The name of the associated type for `Fn` return types.
 pub const FN_OUTPUT_NAME: Symbol = sym::Output;
 
 // Useful type to use with `Result<>` indicate that an error has already
@@ -45,16 +45,16 @@ fn panic_hook(info: &panic::PanicInfo<'_>) {
         TyCtxt::try_print_query_stack();
     }
 
-        #[cfg(windows)]
-        unsafe {
-            if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-                extern "system" {
-                    fn DebugBreak();
-                }
-                // Trigger a debugger if we crashed during bootstrap
-                DebugBreak();
+    #[cfg(windows)]
+    unsafe {
+        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+            extern "system" {
+                fn DebugBreak();
             }
+            // Trigger a debugger if we crashed during bootstrap.
+            DebugBreak();
         }
+    }
 }
 
 pub fn install_panic_hook() {
@@ -80,42 +80,42 @@ pub struct QueryMsg {
 }
 
 /// A sequence of these messages induce a trace of query-based incremental compilation.
-/// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
+// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
 #[derive(Clone,Debug)]
 pub enum ProfileQueriesMsg {
-    /// begin a timed pass
+    /// Begin a timed pass.
     TimeBegin(String),
-    /// end a timed pass
+    /// End a timed pass.
     TimeEnd,
-    /// begin a task (see dep_graph::graph::with_task)
+    /// Begin a task (see `dep_graph::graph::with_task`).
     TaskBegin(DepNode),
-    /// end a task
+    /// End a task.
     TaskEnd,
-    /// begin a new query
-    /// can't use `Span` because queries are sent to other thread
+    /// Begin a new query.
+    /// Cannot use `Span` because queries are sent to other thread.
     QueryBegin(SpanData, QueryMsg),
-    /// query is satisfied by using an already-known value for the given key
+    /// Query is satisfied by using an already-known value for the given key.
     CacheHit,
-    /// query requires running a provider; providers may nest, permitting queries to nest.
+    /// Query requires running a provider; providers may nest, permitting queries to nest.
     ProviderBegin,
-    /// query is satisfied by a provider terminating with a value
+    /// Query is satisfied by a provider terminating with a value.
     ProviderEnd,
-    /// dump a record of the queries to the given path
+    /// Dump a record of the queries to the given path.
     Dump(ProfQDumpParams),
-    /// halt the profiling/monitoring background thread
+    /// Halt the profiling/monitoring background thread.
     Halt
 }
 
-/// If enabled, send a message to the profile-queries thread
+/// If enabled, send a message to the profile-queries thread.
 pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) {
     if let Some(s) = sess.profile_channel.borrow().as_ref() {
         s.send(msg).unwrap()
     } else {
-        // Do nothing
+        // Do nothing.
     }
 }
 
-/// Set channel for profile queries channel
+/// Set channel for profile queries channel.
 pub fn profq_set_chan(sess: &Session, s: Sender<ProfileQueriesMsg>) -> bool {
     let mut channel = sess.profile_channel.borrow_mut();
     if channel.is_none() {
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs
index de2a3c4cb22a8..af10404cba395 100644
--- a/src/librustc_borrowck/dataflow.rs
+++ b/src/librustc_borrowck/dataflow.rs
@@ -19,7 +19,6 @@ use rustc::hir;
 use rustc::hir::intravisit;
 use rustc::hir::print as pprust;
 
-
 #[derive(Copy, Clone, Debug)]
 pub enum EntryOrExit {
     Entry,
@@ -92,7 +91,7 @@ fn get_cfg_indices<'a>(id: hir::ItemLocalId,
     index.get(&id).map_or(&[], |v| &v[..])
 }
 
-impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
+impl<'a, 'tcx, O: DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
         assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
         self.local_id_to_index.contains_key(&n)
@@ -225,7 +224,7 @@ pub enum KillFrom {
     Execution,
 }
 
-impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
+impl<'a, 'tcx, O: DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                analysis_name: &'static str,
                body: Option<&hir::Body>,
@@ -500,8 +499,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     }
 }
 
-impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
-//                                ^^^^^^^^^^^^^ only needed for pretty printing
+// N.B. `Clone + 'static` only needed for pretty printing.
+impl<'a, 'tcx, O: DataFlowOperator + Clone + 'static> DataFlowContext<'a, 'tcx, O> {
     pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
         //! Performs the data flow analysis.
 
@@ -538,7 +537,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
     }
 }
 
-impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
+impl<'a, 'b, 'tcx, O: DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
     fn walk_cfg(&mut self,
                 cfg: &cfg::CFG,
                 nodes_po: &[CFGIndex],
@@ -547,7 +546,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
                bits_to_string(in_out), self.dfcx.analysis_name);
         assert!(self.dfcx.bits_per_id > 0);
 
-        // Iterate over nodes in reverse postorder
+        // Iterate over nodes in reverse post-order.
         for &node_index in nodes_po.iter().rev() {
             let node = cfg.graph.node(node_index);
             debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
@@ -631,9 +630,9 @@ fn bits_to_string(words: &[usize]) -> String {
 }
 
 #[inline]
-fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
-                               in_vec: &[usize],
-                               op: &Op) -> bool {
+fn bitwise<Op: BitwiseOperator>(out_vec: &mut [usize],
+                                in_vec: &[usize],
+                                op: &Op) -> bool {
     assert_eq!(out_vec.len(), in_vec.len());
     let mut changed = false;
     for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 42aa9989346fc..f32dc43126540 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -937,8 +937,8 @@ fn codegen_msvc_try(
     bx.store(ret, dest, i32_align);
 }
 
-// Definition of the standard "try" function for Rust using the GNU-like model
-// of exceptions (e.g., the normal semantics of LLVM's landingpad and invoke
+// Definition of the standard `try` function for Rust using the GNU-like model
+// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
 // instructions).
 //
 // This codegen is a little surprising because we always call a shim
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index c1ec2071789eb..0ba5451bd72f5 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1127,10 +1127,10 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker,
     // For this reason, we have organized the arguments we pass to the linker as
     // such:
     //
-    //  1. The local object that LLVM just generated
-    //  2. Local native libraries
-    //  3. Upstream rust libraries
-    //  4. Upstream native libraries
+    // 1. The local object that LLVM just generated
+    // 2. Local native libraries
+    // 3. Upstream rust libraries
+    // 4. Upstream native libraries
     //
     // The rationale behind this ordering is that those items lower down in the
     // list can't depend on items higher up in the list. For example nothing can
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 4c9313a330921..7e5ee25d8ef78 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -967,7 +967,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         bx.range_metadata(llval, 0..2);
                     }
                 }
-                // We store bools as i8 so we need to truncate to i1.
+                // We store bools as `i8` so we need to truncate to `i1`.
                 llval = base::to_immediate(bx, llval, arg.layout);
             }
         }
@@ -1097,7 +1097,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         fn_ret: &ArgType<'tcx, Ty<'tcx>>,
         llargs: &mut Vec<Bx::Value>, is_intrinsic: bool
     ) -> ReturnDest<'tcx, Bx::Value> {
-        // If the return is ignored, we can just return a do-nothing ReturnDest
+        // If the return is ignored, we can just return a do-nothing `ReturnDest`.
         if fn_ret.is_ignore() {
             return ReturnDest::Nothing;
         }
@@ -1106,8 +1106,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 LocalRef::Place(dest) => dest,
                 LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
                 LocalRef::Operand(None) => {
-                    // Handle temporary places, specifically Operand ones, as
-                    // they don't have allocas
+                    // Handle temporary places, specifically `Operand` ones, as
+                    // they don't have `alloca`s.
                     return if fn_ret.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
@@ -1117,8 +1117,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         ReturnDest::IndirectOperand(tmp, index)
                     } else if is_intrinsic {
                         // Currently, intrinsics always need a location to store
-                        // the result. so we create a temporary alloca for the
-                        // result
+                        // the result, so we create a temporary `alloca` for the
+                        // result.
                         let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
                         tmp.storage_live(bx);
                         ReturnDest::IndirectOperand(tmp, index)
@@ -1137,7 +1137,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             if dest.align < dest.layout.align.abi {
                 // Currently, MIR code generation does not create calls
                 // that store directly to fields of packed structs (in
-                // fact, the calls it creates write only to temps),
+                // fact, the calls it creates write only to temps).
                 //
                 // If someone changes that, please update this code path
                 // to create a temporary.
@@ -1232,12 +1232,12 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 }
 
 enum ReturnDest<'tcx, V> {
-    // Do nothing, the return value is indirect or ignored
+    // Do nothing; the return value is indirect or ignored.
     Nothing,
-    // Store the return value to the pointer
+    // Store the return value to the pointer.
     Store(PlaceRef<'tcx, V>),
-    // Stores an indirect return value to an operand local place
+    // Store an indirect return value to an operand local place.
     IndirectOperand(PlaceRef<'tcx, V>, mir::Local),
-    // Stores a direct return value to an operand local place
+    // Store a direct return value to an operand local place.
     DirectOperand(mir::Local)
 }
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index cd32d6f484d73..27311d0a8fbf1 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
                 bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix))
             };
             PlaceRef {
-                // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
+                // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types.
                 llval: bx.pointercast(llval, bx.cx().type_ptr_to(bx.cx().backend_type(field))),
                 llextra: if bx.cx().type_has_metadata(field.ty) {
                     self.llextra
@@ -134,7 +134,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
 
         // Simple cases, which don't need DST adjustment:
         //   * no metadata available - just log the case
-        //   * known alignment - sized types, [T], str or a foreign type
+        //   * known alignment - sized types, `[T]`, `str` or a foreign type
         //   * packed struct - there is no alignment padding
         match field.ty.sty {
             _ if self.llextra.is_none() => {
@@ -156,18 +156,19 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
         }
 
         // We need to get the pointer manually now.
-        // We do this by casting to a *i8, then offsetting it by the appropriate amount.
+        // We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
         // We do this instead of, say, simply adjusting the pointer from the result of a GEP
         // because the field may have an arbitrary alignment in the LLVM representation
         // anyway.
         //
         // To demonstrate:
-        //   struct Foo<T: ?Sized> {
-        //      x: u16,
-        //      y: T
-        //   }
         //
-        // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
+        //     struct Foo<T: ?Sized> {
+        //         x: u16,
+        //         y: T
+        //     }
+        //
+        // The type `Foo<Foo<Trait>>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that
         // the `y` field has 16-bit alignment.
 
         let meta = self.llextra;
@@ -180,9 +181,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
         // Bump the unaligned offset up to the appropriate alignment using the
         // following expression:
         //
-        //   (unaligned offset + (align - 1)) & -align
+        //     (unaligned offset + (align - 1)) & -align
 
-        // Calculate offset
+        // Calculate offset.
         let align_sub_1 = bx.sub(unsized_align, bx.cx().const_usize(1u64));
         let and_lhs = bx.add(unaligned_offset, align_sub_1);
         let and_rhs = bx.neg(unsized_align);
@@ -190,11 +191,11 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
 
         debug!("struct_field_ptr: DST field offset: {:?}", offset);
 
-        // Cast and adjust pointer
+        // Cast and adjust pointer.
         let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
         let byte_ptr = bx.gep(byte_ptr, &[offset]);
 
-        // Finally, cast back to the type expected
+        // Finally, cast back to the type expected.
         let ll_fty = bx.cx().backend_type(field);
         debug!("struct_field_ptr: Field type is {:?}", ll_fty);
 
@@ -235,7 +236,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
                     // We use `i1` for bytes that are always `0` or `1`,
                     // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
                     // let LLVM interpret the `i1` as signed, because
-                    // then `i1 1` (i.e., E::B) is effectively `i8 -1`.
+                    // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
                     layout::Int(_, signed) => !discr_scalar.is_bool() && signed,
                     _ => false
                 };
@@ -248,9 +249,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
             } => {
                 let niche_llty = bx.cx().immediate_backend_type(discr.layout);
                 if niche_variants.start() == niche_variants.end() {
-                    // FIXME(eddyb) Check the actual primitive type here.
+                    // FIXME(eddyb): check the actual primitive type here.
                     let niche_llval = if niche_start == 0 {
-                        // HACK(eddyb) Using `c_null` as it works on all types.
+                        // HACK(eddyb): using `c_null` as it works on all types.
                         bx.cx().const_null(niche_llty)
                     } else {
                         bx.cx().const_uint_big(niche_llty, niche_start)
@@ -314,7 +315,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
                 if variant_index != dataful_variant {
                     if bx.cx().sess().target.target.arch == "arm" ||
                        bx.cx().sess().target.target.arch == "aarch64" {
-                        // Issue #34427: As workaround for LLVM bug on ARM,
+                        // FIXME(#34427): as workaround for LLVM bug on ARM,
                         // use memset of 0 before assigning niche value.
                         let fill_byte = bx.cx().const_u8(0);
                         let size = bx.cx().const_usize(self.layout.size.bytes());
@@ -326,9 +327,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
                     let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                     let niche_value = (niche_value as u128)
                         .wrapping_add(niche_start);
-                    // FIXME(eddyb) Check the actual primitive type here.
+                    // FIXME(eddyb): check the actual primitive type here.
                     let niche_llval = if niche_value == 0 {
-                        // HACK(eddyb) Using `c_null` as it works on all types.
+                        // HACK(eddyb): using `c_null` as it works on all types.
                         bx.cx().const_null(niche_llty)
                     } else {
                         bx.cx().const_uint_big(niche_llty, niche_value)
@@ -429,10 +430,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         _ => bug!("promoteds should have an allocation: {:?}", val),
                     },
                     Err(_) => {
-                        // this is unreachable as long as runtime
+                        // This is unreachable as long as runtime
                         // and compile-time agree on values
-                        // With floats that won't always be true
-                        // so we generate an abort
+                        // With floats that won't always be true,
+                        // so we generate an abort.
                         bx.abort();
                         let llval = bx.cx().const_undef(
                             bx.cx().type_ptr_to(bx.cx().backend_type(layout))
@@ -502,7 +503,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
 
                         // Cast the place pointer type to the new
-                        // array or slice type (*[%_; new_len]).
+                        // array or slice type (`*[%_; new_len]`).
                         subslice.llval = bx.pointercast(subslice.llval,
                             bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)));
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f9a12c19e4276..937085c8ad8e8 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -196,7 +196,7 @@ declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
 
 impl UnsafeCode {
     fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) {
-        // This comes from a macro that has #[allow_internal_unsafe].
+        // This comes from a macro that has `#[allow_internal_unsafe]`.
         if span.allows_unsafe() {
             return;
         }
@@ -216,7 +216,7 @@ impl EarlyLintPass for UnsafeCode {
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::Block(ref blk, _) = e.node {
-            // Don't warn about generated blocks, that'll just pollute the output.
+            // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
                 self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
             }
@@ -335,7 +335,7 @@ impl MissingDoc {
 
         // Only check publicly-visible items, using the result from the privacy pass.
         // It's an option so the crate root can also use this function (it doesn't
-        // have a NodeId).
+        // have a `NodeId`).
         if let Some(id) = id {
             if !cx.access_levels.is_exported(id) {
                 return;
@@ -389,7 +389,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
             hir::ItemKind::Struct(..) => "a struct",
             hir::ItemKind::Union(..) => "a union",
             hir::ItemKind::Trait(.., ref trait_item_refs) => {
-                // Issue #11592, traits are always considered exported, even when private.
+                // Issue #11592: traits are always considered exported, even when private.
                 if let hir::VisibilityKind::Inherited = it.vis.node {
                     self.private_traits.insert(it.hir_id);
                     for trait_item_ref in trait_item_refs {
@@ -401,7 +401,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
             }
             hir::ItemKind::Ty(..) => "a type alias",
             hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
-                // If the trait is private, add the impl items to private_traits so they don't get
+                // If the trait is private, add the impl items to `private_traits` so they don't get
                 // reported for missing docs.
                 let real_trait = trait_ref.path.res.def_id();
                 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
@@ -1215,7 +1215,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
         use rustc::ty::fold::TypeFoldable;
         use rustc::ty::Predicate::*;
 
-
         if cx.tcx.features().trivial_bounds {
             let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
             let predicates = cx.tcx.predicates_of(def_id);
@@ -1464,7 +1463,7 @@ impl KeywordIdents {
             _ => return,
         };
 
-        // don't lint `r#foo`
+        // Don't lint `r#foo`.
         if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
             return;
         }
@@ -1717,8 +1716,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
                 );
                 err.emit();
             }
-
         }
     }
-
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index db43ea0558cc7..3bf0f7e04d295 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -576,7 +576,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Adds a suggestion to errors where a `impl Trait` is returned.
     ///
     /// ```text
-    /// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as
+    /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
     ///       a constraint
     ///    |
     /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
@@ -652,7 +652,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         diag.span_suggestion(
                             span,
                             &format!(
-                                "to allow this impl Trait to capture borrowed data with lifetime \
+                                "to allow this `impl Trait` to capture borrowed data with lifetime \
                                  `{}`, add `{}` as a constraint",
                                 fr_name, suggestable_fr_name,
                             ),
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 91106ebd77e07..7ca54a430a505 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -289,9 +289,9 @@ pub enum BlockFrame {
     /// Evaluation is currently within a statement.
     ///
     /// Examples include:
-    ///  1. `EXPR;`
-    ///  2. `let _ = EXPR;`
-    ///  3. `let x = EXPR;`
+    /// 1. `EXPR;`
+    /// 2. `let _ = EXPR;`
+    /// 3. `let x = EXPR;`
     Statement {
         /// If true, then statement discards result from evaluating
         /// the expression (such as examples 1 and 2 above).
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 1895d4871552e..2c84364216633 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -90,7 +90,7 @@
 //!
 //! Note though that as a side-effect of creating a codegen units per
 //! source-level module, functions from the same module will be available for
-//! inlining, even when they are not marked #[inline].
+//! inlining, even when they are not marked `#[inline]`.
 
 use std::collections::hash_map::Entry;
 use std::cmp;
@@ -152,7 +152,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // In the next step, we use the inlining map to determine which additional
     // monomorphizations have to go into each codegen unit. These additional
     // monomorphizations can be drop-glue, functions from external crates, and
-    // local functions the definition of which is marked with #[inline].
+    // local functions the definition of which is marked with `#[inline]`.
     let mut post_inlining = place_inlined_mono_items(initial_partitioning,
                                                             inlining_map);
 
@@ -166,7 +166,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         internalize_symbols(tcx, &mut post_inlining, inlining_map);
     }
 
-    // Finally, sort by codegen unit name, so that we get deterministic results
+    // Finally, sort by codegen unit name, so that we get deterministic results.
     let PostInliningPartitioning {
         codegen_units: mut result,
         mono_item_placements: _,
@@ -258,8 +258,8 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         roots.insert(mono_item);
     }
 
-    // always ensure we have at least one CGU; otherwise, if we have a
-    // crate with just types (for example), we could wind up with no CGU
+    // Always ensure we have at least one CGU; otherwise, if we have a
+    // crate with just types (for example), we could wind up with no CGU.
     if codegen_units.is_empty() {
         let codegen_unit_name = fallback_cgu_name(cgu_name_builder);
         codegen_units.insert(codegen_unit_name.clone(),
@@ -300,10 +300,10 @@ fn mono_item_visibility(
     export_generics: bool,
 ) -> Visibility {
     let instance = match mono_item {
-        // This is pretty complicated, go below
+        // This is pretty complicated; see below.
         MonoItem::Fn(instance) => instance,
 
-        // Misc handling for generics and such, but otherwise
+        // Misc handling for generics and such, but otherwise:
         MonoItem::Static(def_id) => {
             return if tcx.is_reachable_non_generic(*def_id) {
                 *can_be_internalized = false;
@@ -358,11 +358,10 @@ fn mono_item_visibility(
 
     let is_generic = instance.substs.non_erasable_generics().next().is_some();
 
-    // Upstream `DefId` instances get different handling than local ones
+    // Upstream `DefId` instances get different handling than local ones.
     if !def_id.is_local() {
         return if export_generics && is_generic {
-            // If it is a upstream monomorphization
-            // and we export generics, we must make
+            // If it is a upstream monomorphization and we export generics, we must make
             // it available to downstream crates.
             *can_be_internalized = false;
             default_visibility(tcx, def_id, true)
@@ -374,20 +373,16 @@ fn mono_item_visibility(
     if is_generic {
         if export_generics {
             if tcx.is_unreachable_local_definition(def_id) {
-                // This instance cannot be used
-                // from another crate.
+                // This instance cannot be used from another crate.
                 Visibility::Hidden
             } else {
-                // This instance might be useful in
-                // a downstream crate.
+                // This instance might be useful in a downstream crate.
                 *can_be_internalized = false;
                 default_visibility(tcx, def_id, true)
             }
         } else {
-            // We are not exporting generics or
-            // the definition is not reachable
-            // for downstream crates, we can
-            // internalize its instantiations.
+            // We are not exporting generics or the definition is not reachable
+            // for downstream crates, we can internalize its instantiations.
             Visibility::Hidden
         }
     } else {
@@ -449,19 +444,19 @@ fn default_visibility(tcx: TyCtxt<'_, '_, '_>, id: DefId, is_generic: bool) -> V
         return Visibility::Default
     }
 
-    // Generic functions never have export level C
+    // Generic functions never have export-level C.
     if is_generic {
         return Visibility::Hidden
     }
 
     // Things with export level C don't get instantiated in
-    // downstream crates
+    // downstream crates.
     if !id.is_local() {
         return Visibility::Hidden
     }
 
     // C-export level items remain at `Default`, all other internal
-    // items become `Hidden`
+    // items become `Hidden`.
     match tcx.reachable_non_generics(id.krate).get(&id) {
         Some(SymbolExportLevel::C) => Visibility::Default,
         _ => Visibility::Hidden,
@@ -519,7 +514,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
     let single_codegen_unit = initial_cgus.len() == 1;
 
     for old_codegen_unit in initial_cgus {
-        // Collect all items that need to be available in this codegen unit
+        // Collect all items that need to be available in this codegen unit.
         let mut reachable = FxHashSet::default();
         for root in old_codegen_unit.items().keys() {
             follow_inlining(*root, inlining_map, &mut reachable);
@@ -527,10 +522,10 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
 
         let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone());
 
-        // Add all monomorphizations that are not already there
+        // Add all monomorphizations that are not already there.
         for mono_item in reachable {
             if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
-                // This is a root, just copy it over
+                // This is a root, just copy it over.
                 new_codegen_unit.items_mut().insert(mono_item, *linkage);
             } else {
                 if roots.contains(&mono_item) {
@@ -538,7 +533,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
                           {:?}", mono_item);
                 }
 
-                // This is a cgu-private copy
+                // This is a CGU-private copy.
                 new_codegen_unit.items_mut().insert(
                     mono_item,
                     (Linkage::Internal, Visibility::Default),
@@ -547,7 +542,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
 
             if !single_codegen_unit {
                 // If there is more than one codegen unit, we need to keep track
-                // in which codegen units each monomorphization is placed:
+                // in which codegen units each monomorphization is placed.
                 match mono_item_placements.entry(mono_item) {
                     Entry::Occupied(e) => {
                         let placement = e.into_mut();
@@ -656,8 +651,8 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                 mono_item: MonoItem<'tcx>)
-                                                 -> Option<DefId> {
+                                                mono_item: MonoItem<'tcx>)
+                                                -> Option<DefId> {
     match mono_item {
         MonoItem::Fn(instance) => {
             let def_id = match instance.def {
@@ -709,10 +704,10 @@ fn compute_codegen_unit_name(tcx: TyCtxt<'_, '_, '_>,
                              volatile: bool,
                              cache: &mut CguNameCache)
                              -> InternedString {
-    // Find the innermost module that is not nested within a function
+    // Find the innermost module that is not nested within a function.
     let mut current_def_id = def_id;
     let mut cgu_def_id = None;
-    // Walk backwards from the item we want to find the module for:
+    // Walk backwards from the item we want to find the module for.
     loop {
         if current_def_id.index == CRATE_DEF_INDEX {
             if cgu_def_id.is_none() {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 89c4a9106a477..6a17a84517e4a 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -1,4 +1,4 @@
-// Validate AST before lowering it to HIR
+// Validate AST before lowering it to HIR.
 //
 // This pass is supposed to catch things that fit into AST data structures,
 // but not permitted by the language. It runs after expansion when AST is frozen,
@@ -56,7 +56,7 @@ struct AstValidator<'a> {
 
     /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
     /// Nested `impl Trait` _is_ allowed in associated type position,
-    /// e.g `impl Iterator<Item=impl Debug>`
+    /// e.g., `impl Iterator<Item = impl Debug>`.
     outer_impl_trait: Option<OuterImplTrait>,
 
     /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
@@ -94,9 +94,9 @@ impl<'a> AstValidator<'a> {
     }
 
     fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) {
-        // rust-lang/rust#57979: bug in old visit_generic_args called
-        // walk_ty rather than visit_ty, skipping outer `impl Trait`
-        // if it happened to occur at `type_binding.ty`
+        // rust-lang/rust#57979: bug in old `visit_generic_args` called
+        // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
+        // if it happened to occur at `type_binding.ty`.
         if let TyKind::ImplTrait(..) = type_binding.ty.node {
             self.warning_period_57979_didnt_record_next_impl_trait = true;
         }
@@ -104,9 +104,9 @@ impl<'a> AstValidator<'a> {
     }
 
     fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) {
-        // rust-lang/rust#57979: bug in old visit_generic_args called
-        // walk_ty rather than visit_ty, skippping outer `impl Trait`
-        // if it happened to occur at `ty`
+        // rust-lang/rust#57979: bug in old `visit_generic_args` called
+        // `walk_ty` rather than `visit_ty`, skippping outer `impl Trait`
+        // if it happened to occur at `ty`.
         if let TyKind::ImplTrait(..) = ty.node {
             self.warning_period_57979_didnt_record_next_impl_trait = true;
         }
@@ -117,10 +117,10 @@ impl<'a> AstValidator<'a> {
         let only_recorded_since_pull_request_57730 =
             self.warning_period_57979_didnt_record_next_impl_trait;
 
-        // (this flag is designed to be set to true and then only
+        // (This flag is designed to be set to `true`, and then only
         // reach the construction point for the outer impl trait once,
         // so its safe and easiest to unconditionally reset it to
-        // false)
+        // false.)
         self.warning_period_57979_didnt_record_next_impl_trait = false;
 
         OuterImplTrait {
@@ -128,7 +128,7 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    // Mirrors visit::walk_ty, but tracks relevant state
+    // Mirrors `visit::walk_ty`, but tracks relevant state.
     fn walk_ty(&mut self, t: &'a Ty) {
         match t.node {
             TyKind::ImplTrait(..) => {
@@ -619,15 +619,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     // Auto traits cannot have generics, super traits nor contain items.
                     if !generics.params.is_empty() {
                         struct_span_err!(self.session, item.span, E0567,
-                                        "auto traits cannot have generic parameters").emit();
+                            "auto traits cannot have generic parameters"
+                        ).emit();
                     }
                     if !bounds.is_empty() {
                         struct_span_err!(self.session, item.span, E0568,
-                                        "auto traits cannot have super traits").emit();
+                            "auto traits cannot have super traits"
+                        ).emit();
                     }
                     if !trait_items.is_empty() {
                         struct_span_err!(self.session, item.span, E0380,
-                                "auto traits cannot have methods or associated items").emit();
+                            "auto traits cannot have methods or associated items"
+                        ).emit();
                     }
                 }
                 self.no_questions_in_bounds(bounds, "supertraits", true);
@@ -699,7 +702,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_foreign_item(self, fi)
     }
 
-    // Mirrors visit::walk_generic_args, but tracks relevant state
+    // Mirrors `visit::walk_generic_args`, but tracks relevant state.
     fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
         match *generic_args {
             GenericArgs::AngleBracketed(ref data) => {
@@ -718,7 +721,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     generic_args.span(),
                 );
 
-                // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
+                // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
                 // are allowed to contain nested `impl Trait`.
                 self.with_impl_trait(None, |this| {
                     walk_list!(this, visit_assoc_type_binding_from_generic_args, &data.bindings);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 9b9cf80f822b0..fb5c1b1953f08 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2134,7 +2134,7 @@ impl<'a> Resolver<'a> {
                                       record_used_id: Option<NodeId>,
                                       path_span: Span)
                                       -> Option<LexicalScopeBinding<'a>> {
-        assert!(ns == TypeNS  || ns == ValueNS);
+        assert!(ns == TypeNS || ns == ValueNS);
         if ident.name == kw::Invalid {
             return Some(LexicalScopeBinding::Res(Res::Err));
         }
@@ -2530,10 +2530,12 @@ impl<'a> Resolver<'a> {
 
         match item.node {
             ItemKind::Ty(_, ref generics) |
-            ItemKind::Fn(_, _, ref generics, _) |
-            ItemKind::Existential(_, ref generics) => {
-                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind),
-                                             |this| visit::walk_item(this, item));
+            ItemKind::Existential(_, ref generics) |
+            ItemKind::Fn(_, _, ref generics, _) => {
+                self.with_generic_param_rib(
+                    HasGenericParams(generics, ItemRibKind),
+                    |this| visit::walk_item(this, item)
+                );
             }
 
             ItemKind::Enum(_, ref generics) |
@@ -2967,7 +2969,7 @@ impl<'a> Resolver<'a> {
         binding_map
     }
 
-    // check that all of the arms in an or-pattern have exactly the
+    // Checks that all of the arms in an or-pattern have exactly the
     // same set of bindings, with the same binding modes for each.
     fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
         if pats.is_empty() {
@@ -2987,7 +2989,7 @@ impl<'a> Resolver<'a> {
                 let map_j = self.binding_mode_map(&q);
                 for (&key, &binding_i) in &map_i {
                     if map_j.is_empty() {                   // Account for missing bindings when
-                        let binding_error = missing_vars    // map_j has none.
+                        let binding_error = missing_vars    // `map_j` has none.
                             .entry(key.name)
                             .or_insert(BindingError {
                                 name: key.name,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index cc054adee7bea..72ac041d2e57d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -47,14 +47,14 @@ pub trait AstConv<'gcx, 'tcx> {
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
                                  -> &'tcx ty::GenericPredicates<'tcx>;
 
-    /// What lifetime should we use when a lifetime is omitted (and not elided)?
+    /// Returns the lifetime to use when a lifetime is omitted (and not elided).
     fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
                 -> Option<ty::Region<'tcx>>;
 
-    /// What type should we use when a type is omitted?
+    /// Returns the type to use when a type is omitted.
     fn ty_infer(&self, span: Span) -> Ty<'tcx>;
 
-    /// Same as ty_infer, but with a known type parameter definition.
+    /// Same as `ty_infer`, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
                         _def: &ty::GenericParamDef,
                         span: Span) -> Ty<'tcx> {
@@ -376,8 +376,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
             err.emit();
 
-            (provided > required, // `suppress_error`
-             potential_assoc_types)
+            (
+                provided > required, // `suppress_error`
+                potential_assoc_types,
+            )
         };
 
         if reported_late_bound_region_err.is_none()
@@ -556,7 +558,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 
     /// Given the type/lifetime/const arguments provided to some path (along with
-    /// an implicit `Self`, if this is a trait reference) returns the complete
+    /// an implicit `Self`, if this is a trait reference), returns the complete
     /// set of substitutions. This may involve applying defaulted type parameters.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
@@ -708,8 +710,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     /// are disallowed. Otherwise, they are pushed onto the vector given.
     pub fn instantiate_mono_trait_ref(&self,
         trait_ref: &hir::TraitRef,
-        self_ty: Ty<'tcx>)
-        -> ty::TraitRef<'tcx>
+        self_ty: Ty<'tcx>
+    ) -> ty::TraitRef<'tcx>
     {
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
 
@@ -724,8 +726,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         trait_ref: &hir::TraitRef,
         self_ty: Ty<'tcx>,
         poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
-        speculative: bool)
-        -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
+        speculative: bool,
+    ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
     {
         let trait_def_id = trait_ref.trait_def_id();
 
@@ -851,13 +853,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             // trait SubTrait: SuperTrait<int> { }
             // trait SuperTrait<A> { type T; }
             //
-            // ... B : SubTrait<T=foo> ...
+            // ... B: SubTrait<T = foo> ...
             // ```
             //
             // We want to produce `<B as SuperTrait<int>>::T == foo`.
 
             // Find any late-bound regions declared in `ty` that are not
-            // declared in the trait-ref. These are not wellformed.
+            // declared in the trait-ref. These are not well-formed.
             //
             // Example:
             //
@@ -1716,7 +1718,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let span = path.span;
         match path.res {
             Res::Def(DefKind::Existential, did) => {
-                // Check for desugared impl trait.
+                // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
                 self.prohibit_generics(item_segment.1);
@@ -1767,19 +1769,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     &tcx.hir().local_def_id_from_hir_id(hir_id)];
                 tcx.mk_ty_param(index, tcx.hir().name_by_hir_id(hir_id).as_interned_str())
             }
-            Res::SelfTy(_, Some(def_id)) => {
-                // `Self` in impl (we know the concrete type).
-                assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(&path.segments);
-                // Try to evaluate any array length constants
-                self.normalize_ty(span, tcx.at(span).type_of(def_id))
-            }
             Res::SelfTy(Some(_), None) => {
                 // `Self` in trait.
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(&path.segments);
                 tcx.mk_self_type()
             }
+            Res::SelfTy(_, Some(def_id)) => {
+                // `Self` in impl (we know the concrete type).
+                assert_eq!(opt_self_ty, None);
+                self.prohibit_generics(&path.segments);
+                // Try to evaluate any array length constants.
+                self.normalize_ty(span, tcx.at(span).type_of(def_id))
+            }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
                 self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
@@ -1829,7 +1831,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
             hir::TyKind::Rptr(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
-                debug!("Ref r={:?}", r);
+                debug!("ast_ty_to_ty: r={:?}", r);
                 let t = self.ast_ty_to_ty(&mt.ty);
                 tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
             }
@@ -1856,7 +1858,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             hir::TyKind::Def(item_id, ref lifetimes) => {
                 let did = tcx.hir().local_def_id_from_hir_id(item_id.id);
                 self.impl_trait_ty_to_ty(did, lifetimes)
-            },
+            }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
                 let ty = self.ast_ty_to_ty(qself);
@@ -1889,9 +1891,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(ast_ty.span)
             }
-            hir::TyKind::Err => {
-                tcx.types.err
-            }
             hir::TyKind::CVarArgs(lt) => {
                 let va_list_did = match tcx.lang_items().va_list() {
                     Some(did) => did,
@@ -1901,6 +1900,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 let region = self.ast_region_to_region(&lt, None);
                 tcx.type_of(va_list_did).subst(tcx, &[region.into()])
             }
+            hir::TyKind::Err => {
+                tcx.types.err
+            }
         };
 
         self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
@@ -1979,7 +1981,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     _ => bug!()
                 }
             } else {
-                // Replace all parent lifetimes with 'static.
+                // Replace all parent lifetimes with `'static`.
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
                         tcx.lifetimes.re_static.into()
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index d64be24f7538f..aab873323f91e 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -173,7 +173,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             // here, we would coerce from `!` to `?T`.
             let b = self.shallow_resolve(b);
             return if self.shallow_resolve(b).is_ty_var() {
-                // micro-optimization: no need for this if `b` is
+                // Micro-optimization: no need for this if `b` is
                 // already resolved in some way.
                 let diverging_ty = self.next_diverging_ty_var(
                     TypeVariableOrigin::AdjustmentType(self.cause.span));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3ada80b3e8b70..d165c7e2b2cf7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -518,10 +518,10 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// eventually).
     param_env: ty::ParamEnv<'tcx>,
 
-    // Number of errors that had been reported when we started
-    // checking this function. On exit, if we find that *more* errors
-    // have been reported, we will skip regionck and other work that
-    // expects the types within the function to be consistent.
+    /// Number of errors that had been reported when we started
+    /// checking this function. On exit, if we find that *more* errors
+    /// have been reported, we will skip regionck and other work that
+    /// expects the types within the function to be consistent.
     err_count_on_creation: usize,
 
     ret_coercion: Option<RefCell<DynamicCoerceMany<'gcx, 'tcx>>>,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 6f8682e64671c..1bc7119b314e9 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -450,38 +450,38 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             let generics = self.tcx().generics_of(def_id);
 
             let definition_ty = if generics.parent.is_some() {
-                // impl trait
+                // `impl Trait`
                 self.fcx.infer_opaque_definition_from_instantiation(
                     def_id,
                     opaque_defn,
                     instantiated_ty,
                 )
             } else {
-                // prevent
+                // Prevent:
                 // * `fn foo<T>() -> Foo<T>`
                 // * `fn foo<T: Bound + Other>() -> Foo<T>`
-                // from being defining
+                // from being defining.
 
                 // Also replace all generic params with the ones from the existential type
-                // definition so
+                // definition so that
                 // ```rust
                 // existential type Foo<T>: 'static;
                 // fn foo<U>() -> Foo<U> { .. }
                 // ```
-                // figures out the concrete type with `U`, but the stored type is with `T`
+                // figures out the concrete type with `U`, but the stored type is with `T`.
                 instantiated_ty.fold_with(&mut BottomUpFolder {
                     tcx: self.tcx().global_tcx(),
                     ty_op: |ty| {
                         trace!("checking type {:?}", ty);
-                        // find a type parameter
+                        // Find a type parameter.
                         if let ty::Param(..) = ty.sty {
-                            // look it up in the substitution list
+                            // Look it up in the substitution list.
                             assert_eq!(opaque_defn.substs.len(), generics.params.len());
                             for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) {
                                 if let UnpackedKind::Type(subst) = subst.unpack() {
                                     if subst == ty {
-                                        // found it in the substitution list, replace with the
-                                        // parameter from the existential type
+                                        // Found it in the substitution list; replace with the
+                                        // parameter from the existential type.
                                         return self.tcx()
                                             .global_tcx()
                                             .mk_ty_param(param.index, param.name);
@@ -505,16 +505,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                     },
                     lt_op: |region| {
                         match region {
-                            // Skip static and bound regions: they don't
-                            // require substitution.
+                            // Skip static and bound regions: they don't require substitution.
                             ty::ReStatic | ty::ReLateBound(..) => region,
                             _ => {
                                 trace!("checking {:?}", region);
                                 for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
                                     if let UnpackedKind::Lifetime(subst) = subst.unpack() {
                                         if subst == region {
-                                            // found it in the substitution list, replace with the
-                                            // parameter from the existential type
+                                            // Found it in the substitution list; replace with the
+                                            // parameter from the existential type.
                                             let reg = ty::EarlyBoundRegion {
                                                 def_id: p.def_id,
                                                 index: p.index,
@@ -586,8 +585,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
             if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
                 if def_id == defin_ty_def_id {
-                    // Concrete type resolved to the existential type itself
-                    // Force a cycle error
+                    // Concrete type resolved to the existential type itself.
+                    // Force a cycle error.
                     // FIXME(oli-obk): we could just not insert it into `concrete_existential_types`
                     // which simply would make this use not a defining use.
                     self.tcx().at(span).type_of(defin_ty_def_id);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3034cacf6253f..f362263c16e75 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1,6 +1,6 @@
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
-//! with *interprocedural* things -- for example, for a function
+//! with *inter-procedural* things -- for example, for a function
 //! definition, collection will figure out the type and signature of the
 //! function, but it will not visit the *body* of the function in any way,
 //! nor examine type annotations on local variables (that's the job of
@@ -233,7 +233,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
     }
 
     fn set_tainted_by_errors(&self) {
-        // no obvious place to track this, just let it go
+        // no obvious place to track this, so just let it go
     }
 
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
@@ -447,7 +447,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: hir::HirId) {
             }
         }
 
-        // Desugared from `impl Trait` -> visited by the function's return type
+        // Desugared from `impl Trait`, so visited by the function's return type.
         hir::ItemKind::Existential(hir::ExistTy {
             impl_trait_fn: Some(_),
             ..
@@ -1218,7 +1218,7 @@ pub fn checked_type_of<'a, 'tcx>(
                     impl_trait_fn: None,
                     ..
                 }) => find_existential_constraints(tcx, def_id),
-                // existential types desugared from impl Trait
+                // Existential types desugared from `impl Trait`.
                 ItemKind::Existential(hir::ExistTy {
                     impl_trait_fn: Some(owner),
                     ..
@@ -1472,11 +1472,13 @@ fn find_existential_constraints<'a, 'tcx>(
 ) -> Ty<'tcx> {
     use rustc::hir::{ImplItem, Item, TraitItem};
 
+    debug!("find_existential_constraints({:?})", def_id);
+
     struct ConstraintLocator<'a, 'tcx: 'a> {
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         def_id: DefId,
-        // First found type span, actual type, mapping from the existential type's generic
-        // parameters to the concrete type's generic parameters
+        // (first found type span, actual type, mapping from the existential type's generic
+        // parameters to the concrete type's generic parameters)
         //
         // The mapping is an index for each use site of a generic parameter in the concrete type
         //
@@ -1502,18 +1504,21 @@ fn find_existential_constraints<'a, 'tcx>(
                 let span = self.tcx.def_span(def_id);
                 // used to quickly look up the position of a generic parameter
                 let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
-                // skip binder is ok, since we only use this to find generic parameters and their
-                // positions.
+                // Skipping binder is ok, since we only use this to find generic parameters and
+                // their positions.
                 for (idx, subst) in substs.iter().enumerate() {
                     if let UnpackedKind::Type(ty) = subst.unpack() {
                         if let ty::Param(p) = ty.sty {
                             if index_map.insert(p, idx).is_some() {
-                                // there was already an entry for `p`, meaning a generic parameter
-                                // was used twice
+                                // There was already an entry for `p`, meaning a generic parameter
+                                // was used twice.
                                 self.tcx.sess.span_err(
                                     span,
-                                    &format!("defining existential type use restricts existential \
-                                    type by using the generic parameter `{}` twice", p.name),
+                                    &format!(
+                                        "defining existential type use restricts existential \
+                                         type by using the generic parameter `{}` twice",
+                                        p.name
+                                    ),
                                 );
                                 return;
                             }
@@ -1528,8 +1533,8 @@ fn find_existential_constraints<'a, 'tcx>(
                         }
                     }
                 }
-                // compute the index within the existential type for each generic parameter used in
-                // the concrete type
+                // Compute the index within the existential type for each generic parameter used in
+                // the concrete type.
                 let indices = concrete_type
                     .subst(self.tcx, substs)
                     .walk()
@@ -1607,7 +1612,7 @@ fn find_existential_constraints<'a, 'tcx>(
         }
         fn visit_item(&mut self, it: &'tcx Item) {
             let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id);
-            // the existential type itself or its children are not within its reveal scope
+            // The existential type itself or its children are not within its reveal scope.
             if def_id != self.def_id {
                 self.check(def_id);
                 intravisit::walk_item(self, it);
@@ -1615,7 +1620,7 @@ fn find_existential_constraints<'a, 'tcx>(
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem) {
             let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id);
-            // the existential type itself or its children are not within its reveal scope
+            // The existential type itself or its children are not within its reveal scope.
             if def_id != self.def_id {
                 self.check(def_id);
                 intravisit::walk_impl_item(self, it);
@@ -1960,7 +1965,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
                 let opaque_ty = tcx.mk_opaque(def_id, substs);
 
-                // Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`.
+                // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
                 let bounds = compute_bounds(
                     &icx,
                     opaque_ty,
@@ -2006,7 +2011,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     let opaque_ty = tcx.mk_opaque(def_id, substs);
 
-                    // Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`.
+                    // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
                     let bounds = compute_bounds(
                         &icx,
                         opaque_ty,
@@ -2016,7 +2021,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                     );
 
                     if impl_trait_fn.is_some() {
-                        // impl Trait
+                        // opaque types
                         return tcx.arena.alloc(ty::GenericPredicates {
                             parent: None,
                             predicates: bounds.predicates(tcx, opaque_ty),
@@ -2093,7 +2098,7 @@ fn explicit_predicates_of<'a, 'tcx>(
     }
 
     // Collect the predicates that were written inline by the user on each
-    // type parameter (e.g., `<T:Foo>`).
+    // type parameter (e.g., `<T: Foo>`).
     for param in &ast_generics.params {
         if let GenericParamKind::Type { .. } = param.kind {
             let name = param.name.ident().as_interned_str();
@@ -2106,7 +2111,7 @@ fn explicit_predicates_of<'a, 'tcx>(
         }
     }
 
-    // Add in the bounds that appear in the where-clause
+    // Add in the bounds that appear in the where-clause.
     let where_clause = &ast_generics.where_clause;
     for predicate in &where_clause.predicates {
         match predicate {
@@ -2422,7 +2427,7 @@ fn from_target_feature(
             continue;
         }
 
-        // Must be of the form `enable = "..."` ( a string)
+        // Must be of the form `enable = "..."` (a string).
         let value = match item.value_str() {
             Some(value) => value,
             None => {
@@ -2545,7 +2550,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
             if tcx.is_foreign_item(id) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
             } else {
-                // `#[ffi_returns_twice]` is only allowed `extern fn`s
+                // `#[ffi_returns_twice]` is only allowed `extern fn`s.
                 struct_span_err!(
                     tcx.sess,
                     attr.span,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 95f7c2949cb56..024d73ff65bd2 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -379,8 +379,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
 /// A quasi-deprecated helper used in rustdoc and clippy to get
 /// the type from a HIR node.
 pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
-    // In case there are any projections etc, find the "environment"
-    // def-id that will be used to determine the traits/predicates in
+    // In case there are any projections, etc., find the "environment"
+    // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
     let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let env_def_id = tcx.hir().local_def_id_from_hir_id(env_node_id);
@@ -391,8 +391,8 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
 
 pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
         -> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) {
-    // In case there are any projections etc, find the "environment"
-    // def-id that will be used to determine the traits/predicates in
+    // In case there are any projections, etc., find the "environment"
+    // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
     let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
     let env_def_id = tcx.hir().local_def_id_from_hir_id(env_hir_id);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0c00b3b20b5b3..f19e5180939ba 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2443,12 +2443,12 @@ pub struct PolyTrait {
     pub generic_params: Vec<GenericParamDef>,
 }
 
-/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
-/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
-/// it does not preserve mutability or boxes.
+/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
+/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
+/// importantly, it does not preserve mutability or boxes.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub enum Type {
-    /// Structs/enums/traits (most that'd be an `hir::TyKind::Path`).
+    /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
     ResolvedPath {
         path: Path,
         param_names: Option<Vec<GenericBound>>,
@@ -2462,7 +2462,7 @@ pub enum Type {
     /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
     /// arrays, slices, and tuples.
     Primitive(PrimitiveType),
-    /// extern "ABI" fn
+    /// `extern "ABI" fn`
     BareFunction(Box<BareFunctionDecl>),
     Tuple(Vec<Type>),
     Slice(Box<Type>),
@@ -2477,17 +2477,17 @@ pub enum Type {
         type_: Box<Type>,
     },
 
-    // <Type as Trait>::Name
+    // `<Type as Trait>::Name`
     QPath {
         name: String,
         self_type: Box<Type>,
         trait_: Box<Type>
     },
 
-    // _
+    // `_`
     Infer,
 
-    // impl TraitA+TraitB
+    // `impl TraitA + TraitB + ...`
     ImplTrait(Vec<GenericBound>),
 }
 
@@ -2747,7 +2747,6 @@ impl Clean<Type> for hir::Ty {
 
         match self.node {
             TyKind::Never => Never,
-            TyKind::CVarArgs(_) => CVarArgs,
             TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
             TyKind::Rptr(ref l, ref m) => {
                 let lifetime = if l.is_elided() {
@@ -2933,12 +2932,13 @@ impl Clean<Type> for hir::Ty {
                         }
                         ResolvedPath { path, param_names: Some(bounds), did, is_generic, }
                     }
-                    _ => Infer // shouldn't happen
+                    _ => Infer, // shouldn't happen
                 }
             }
             TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
+            TyKind::CVarArgs(_) => CVarArgs,
         }
     }
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 1b38d4879050e..38cde12100056 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,7 +18,6 @@ use crate::core::DocAccessLevels;
 use crate::html::item_type::ItemType;
 use crate::html::render::{self, cache, CURRENT_LOCATION_KEY};
 
-
 /// Helper to render an optional visibility with a space after it (if the
 /// visibility is preset)
 #[derive(Copy, Clone)]
@@ -561,7 +560,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
             if param_names.is_some() {
                 f.write_str("dyn ")?;
             }
-            // Paths like T::Output and Self::Output should be rendered with all segments
+            // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
             resolved_path(f, did, path, is_generic, use_absolute)?;
             tybounds(f, param_names)
         }
@@ -585,7 +584,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 &[] => primitive_link(f, PrimitiveType::Unit, "()"),
                 &[ref one] => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
-                    //carry f.alternate() into this display w/o branching manually
+                    // Carry `f.alternate()` into this display w/o branching manually.
                     fmt::Display::fmt(one, f)?;
                     primitive_link(f, PrimitiveType::Tuple, ",)")
                 }
@@ -638,7 +637,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
                 "&amp;".to_string()
             };
             match **ty {
-                clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
+                clean::Slice(ref bt) => { // `BorrowedRef{ ... Slice(T) }` is `&[T]`
                     match **bt {
                         clean::Generic(_) => {
                             if f.alternate() {
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 27b8a110ca71e..9ef42063f9412 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -171,7 +171,8 @@ fn default_hook(info: &PanicInfo<'_>) {
         }
     };
 
-    let location = info.location().unwrap();  // The current implementation always returns Some
+    // The current implementation always returns `Some`.
+    let location = info.location().unwrap();
 
     let msg = match info.payload().downcast_ref::<&'static str>() {
         Some(s) => *s,
@@ -196,7 +197,7 @@ fn default_hook(info: &PanicInfo<'_>) {
             if let Some(format) = log_backtrace {
                 let _ = backtrace::print(err, format);
             } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
-                let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` \
+                let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
                                        environment variable to display a backtrace.");
             }
         }
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index a01b31e948b4e..bf37ff7ddbd3a 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -173,7 +173,7 @@ impl<'a, 'b> Printer<'a, 'b> {
             Some(symbol) => {
                 match self.format {
                     PrintFormat::Full => write!(self.out, "{}", symbol)?,
-                    // strip the trailing hash if short mode
+                    // Strip the trailing hash if short mode.
                     PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
                 }
             }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index b8a10d90c3c0a..31e898048003d 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -213,7 +213,7 @@ pub struct ParenthesizedArgs {
     /// Overall span
     pub span: Span,
 
-    /// `(A,B)`
+    /// `(A, B)`
     pub inputs: Vec<P<Ty>>,
 
     /// `C`
@@ -1840,7 +1840,7 @@ impl Arg {
     }
 }
 
-/// Header (not the body) of a function declaration.
+/// A header (not the body) of a function declaration.
 ///
 /// E.g., `fn foo(bar: baz)`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 47c79f8466a95..435a3d7b6a22a 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -10,7 +10,7 @@ use rustc_target::spec::abi::Abi;
 use syntax_pos::{Pos, Span};
 
 pub trait AstBuilder {
-    // paths
+    // Paths
     fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
     fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path;
     fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
@@ -69,7 +69,7 @@ pub trait AstBuilder {
                     bounds: ast::GenericBounds)
                     -> ast::GenericParam;
 
-    // statements
+    // Statements
     fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
     fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt;
     fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P<ast::Expr>) -> ast::Stmt;
@@ -83,11 +83,11 @@ pub trait AstBuilder {
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
     fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
 
-    // blocks
+    // Blocks
     fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
     fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
 
-    // expressions
+    // Expressions
     fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr>;
     fn expr_path(&self, path: ast::Path) -> P<ast::Expr>;
     fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr>;
@@ -194,12 +194,12 @@ pub trait AstBuilder {
     fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
                       ident: ast::Ident) -> P<ast::Expr>;
 
-    // items
+    // Items
     fn item(&self, span: Span,
             name: Ident, attrs: Vec<ast::Attribute> , node: ast::ItemKind) -> P<ast::Item>;
 
     fn arg(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::Arg;
-    // FIXME unused self
+    // FIXME: unused `self`
     fn fn_decl(&self, inputs: Vec<ast::Arg> , output: ast::FunctionRetTy) -> P<ast::FnDecl>;
 
     fn item_fn_poly(&self,
@@ -552,7 +552,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         }
     }
 
-    // Generate `let _: Type;`, usually used for type assertions.
+    // Generates `let _: Type;`, which is usually used for type assertions.
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
         let local = P(ast::Local {
             pat: self.pat_wild(span),
@@ -606,7 +606,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(path.span, ast::ExprKind::Path(None, path))
     }
 
-    /// Constructs a QPath expression.
+    /// Constructs a `QPath` expression.
     fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr> {
         self.expr(span, ast::ExprKind::Path(Some(qself), path))
     }
@@ -736,7 +736,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(sp, ast::ExprKind::Cast(expr, ty))
     }
 
-
     fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
         self.expr_call_global(sp, some, vec![expr])
@@ -748,12 +747,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr_path(none)
     }
 
-
     fn expr_break(&self, sp: Span) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Break(None, None))
     }
 
-
     fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Tup(exprs))
     }
@@ -797,22 +794,22 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
-        // Ok(__try_var) pattern
+        // `Ok(__try_var)` pattern
         let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
 
-        // Err(__try_var)  (pattern and expression resp.)
+        // `Err(__try_var)` (pattern and expression respectively)
         let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
         let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
                                             vec![binding_expr.clone()]);
-        // return Err(__try_var)
+        // `return Err(__try_var)`
         let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
 
-        // Ok(__try_var) => __try_var
+        // `Ok(__try_var) => __try_var`
         let ok_arm = self.arm(sp, vec![ok_pat], binding_expr);
-        // Err(__try_var) => return Err(__try_var)
+        // `Err(__try_var) => return Err(__try_var)`
         let err_arm = self.arm(sp, vec![err_pat], err_expr);
 
-        // match head { Ok() => ..., Err() => ... }
+        // `match head { Ok() => ..., Err() => ... }`
         self.expr_match(sp, head, vec![ok_arm, err_arm])
     }
 
@@ -972,7 +969,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         }
     }
 
-    // FIXME unused self
+    // FIXME: unused `self`
     fn fn_decl(&self, inputs: Vec<ast::Arg>, output: ast::FunctionRetTy) -> P<ast::FnDecl> {
         P(ast::FnDecl {
             inputs,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 39fcd29e1b084..abfce660c8041 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -191,24 +191,24 @@ enum PrevTokenKind {
     Other,
 }
 
-/* ident is handled by common.rs */
+// NOTE: `Ident`s are handled by `common.rs`.
 
 #[derive(Clone)]
 pub struct Parser<'a> {
     pub sess: &'a ParseSess,
-    /// the current token:
+    /// The current token.
     pub token: token::Token,
-    /// the span of the current token:
+    /// The span of the current token.
     pub span: Span,
-    /// the span of the previous token:
     meta_var_span: Option<Span>,
+    /// The span of the previous token.
     pub prev_span: Span,
-    /// the previous token kind
+    /// The kind of the previous troken.
     prev_token_kind: PrevTokenKind,
     restrictions: Restrictions,
-    /// Used to determine the path to externally loaded source files
+    /// Used to determine the path to externally loaded source files.
     crate directory: Directory<'a>,
-    /// Whether to parse sub-modules in other files.
+    /// `true` to parse sub-modules in other files.
     pub recurse_into_file_modules: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
@@ -217,7 +217,7 @@ pub struct Parser<'a> {
     crate expected_tokens: Vec<TokenType>,
     crate token_cursor: TokenCursor,
     desugar_doc_comments: bool,
-    /// Whether we should configure out of line modules as we parse.
+    /// `true` we should configure out of line modules as we parse.
     pub cfg_mods: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
     /// required in order to detect extra leading left angle brackets (`<` characters) and error
@@ -2680,8 +2680,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    // parse a stream of tokens into a list of TokenTree's,
-    // up to EOF.
+    /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF.
     pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> {
         let mut tts = Vec::new();
         while self.token != token::Eof {
@@ -5344,9 +5343,10 @@ impl<'a> Parser<'a> {
                 // Parse optional `for<'a, 'b>`.
                 // This `for` is parsed greedily and applies to the whole predicate,
                 // the bounded type can have its own `for` applying only to it.
-                // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/>
-                // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/>
-                // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/>
+                // Examples:
+                // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
+                // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
+                // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
                 let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
 
                 // Parse type with mandatory colon and (possibly empty) bounds,
@@ -5478,17 +5478,17 @@ impl<'a> Parser<'a> {
             this.look_ahead(n + 1, |t| t != &token::ModSep)
         };
 
-        // Parse optional self parameter of a method.
-        // Only a limited set of initial token sequences is considered self parameters, anything
+        // Parse optional `self` parameter of a method.
+        // Only a limited set of initial token sequences is considered `self` parameters; anything
         // else is parsed as a normal function parameter list, so some lookahead is required.
         let eself_lo = self.span;
         let (eself, eself_ident, eself_hi) = match self.token {
             token::BinOp(token::And) => {
-                // &self
-                // &mut self
-                // &'lt self
-                // &'lt mut self
-                // &not_self
+                // `&self`
+                // `&mut self`
+                // `&'lt self`
+                // `&'lt mut self`
+                // `&not_self`
                 (if isolated_self(self, 1) {
                     self.bump();
                     SelfKind::Region(None, Mutability::Immutable)
@@ -5514,10 +5514,10 @@ impl<'a> Parser<'a> {
                 }, expect_ident(self), self.prev_span)
             }
             token::BinOp(token::Star) => {
-                // *self
-                // *const self
-                // *mut self
-                // *not_self
+                // `*self`
+                // `*const self`
+                // `*mut self`
+                // `*not_self`
                 // Emit special error for `self` cases.
                 let msg = "cannot pass `self` by raw pointer";
                 (if isolated_self(self, 1) {
@@ -5540,8 +5540,8 @@ impl<'a> Parser<'a> {
             }
             token::Ident(..) => {
                 if isolated_self(self, 0) {
-                    // self
-                    // self: TYPE
+                    // `self`
+                    // `self: TYPE`
                     let eself_ident = expect_ident(self);
                     let eself_hi = self.prev_span;
                     (if self.eat(&token::Colon) {
@@ -5552,8 +5552,8 @@ impl<'a> Parser<'a> {
                     }, eself_ident, eself_hi)
                 } else if self.token.is_keyword(kw::Mut) &&
                           isolated_self(self, 1) {
-                    // mut self
-                    // mut self: TYPE
+                    // `mut self`
+                    // `mut self: TYPE`
                     self.bump();
                     let eself_ident = expect_ident(self);
                     let eself_hi = self.prev_span;
@@ -5580,7 +5580,7 @@ impl<'a> Parser<'a> {
     {
         self.expect(&token::OpenDelim(token::Paren))?;
 
-        // Parse optional self argument
+        // Parse optional self argument.
         let self_arg = self.parse_self_arg()?;
 
         // Parse the rest of the function parameter list.
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b81dc53ef6836..44e1f5398d3e0 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1715,7 +1715,7 @@ impl<'a> State<'a> {
         match els {
             Some(_else) => {
                 match _else.node {
-                    // "another else-if"
+                    // Another `else if` block.
                     ast::ExprKind::If(ref i, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
@@ -1725,7 +1725,7 @@ impl<'a> State<'a> {
                         self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
-                    // "another else-if-let"
+                    // Another `else if let` block.
                     ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
@@ -1738,14 +1738,14 @@ impl<'a> State<'a> {
                         self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
-                    // "final else"
+                    // Final `else` block.
                     ast::ExprKind::Block(ref b, _) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         self.s.word(" else ")?;
                         self.print_block(b)
                     }
-                    // BLEAH, constraints would be great here
+                    // Constraints would be great here!
                     _ => {
                         panic!("print_if saw if with weird alternative");
                     }
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index 9afcb7c4621c9..d577243fb3dcd 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -57,7 +57,8 @@ impl<T: 'static> P<T> {
     {
         f(*self.ptr)
     }
-    /// Equivalent to and_then(|x| x)
+
+    /// Equivalent to `and_then(|x| x)`.
     pub fn into_inner(self) -> T {
         *self.ptr
     }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index eb516b5c7c62f..ba57055b8e009 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -499,7 +499,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
     walk_list!(visitor, visit_attribute, param.attrs.iter());
     walk_list!(visitor, visit_param_bound, &param.bounds);
     match param.kind {
-        GenericParamKind::Lifetime => {}
+        GenericParamKind::Lifetime => (),
         GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
         GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
     }
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 7e3082a87d992..ffec667aba5d3 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -922,8 +922,7 @@ impl<'a> MethodDef<'a> {
                      arg_types: Vec<(Ident, P<ast::Ty>)>,
                      body: P<Expr>)
                      -> ast::ImplItem {
-
-        // create the generics that aren't for Self
+        // Create the generics that aren't for `Self`.
         let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
 
         let args = {
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index 5b8f4f35f2dd1..de8b689396fb9 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -245,8 +245,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         // First up, make sure we're checking a bare function. If we're not then
         // we're just not interested in this item.
         //
-        // If we find one, try to locate a `#[proc_macro_derive]` attribute on
-        // it.
+        // If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
         let is_fn = match item.node {
             ast::ItemKind::Fn(..) => true,
             _ => false,
@@ -259,7 +258,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                 if let Some(prev_attr) = found_attr {
                     let msg = if attr.path.segments[0].ident.name ==
                                  prev_attr.path.segments[0].ident.name {
-                        format!("Only one `#[{}]` attribute is allowed on any given function",
+                        format!("only one `#[{}]` attribute is allowed on any given function",
                                 attr.path)
                     } else {
                         format!("`#[{}]` and `#[{}]` attributes cannot both be applied \
@@ -267,7 +266,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                     };
 
                     self.handler.struct_span_err(attr.span, &msg)
-                        .span_note(prev_attr.span, "Previous attribute here")
+                        .span_note(prev_attr.span, "previous attribute here")
                         .emit();
 
                     return;
diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
index 2e2a77b92ca53..7e819e2b34e38 100644
--- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
@@ -1,23 +1,21 @@
 // ignore-cross-compile
 
-
 // The general idea of this test is to enumerate all "interesting" expressions and check that
-// `parse(print(e)) == e` for all `e`.  Here's what's interesting, for the purposes of this test:
+// `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test:
 //
-//  1. The test focuses on expression nesting, because interactions between different expression
-//     types are harder to test manually than single expression types in isolation.
+// 1. The test focuses on expression nesting, because interactions between different expression
+//    types are harder to test manually than single expression types in isolation.
 //
-//  2. The test only considers expressions of at most two nontrivial nodes.  So it will check `x +
-//     x` and `x + (x - x)` but not `(x * x) + (x - x)`.  The assumption here is that the correct
-//     handling of an expression might depend on the expression's parent, but doesn't depend on its
-//     siblings or any more distant ancestors.
+// 2. The test only considers expressions of at most two nontrivial nodes. So it will check `x +
+//    x` and `x + (x - x)` but not `(x * x) + (x - x)`. The assumption here is that the correct
+//    handling of an expression might depend on the expression's parent, but doesn't depend on its
+//    siblings or any more distant ancestors.
 //
-// 3. The test only checks certain expression kinds.  The assumption is that similar expression
-//    types, such as `if` and `while` or `+` and `-`,  will be handled identically in the printer
-//    and parser.  So if all combinations of exprs involving `if` work correctly, then combinations
+// 3. The test only checks certain expression kinds. The assumption is that similar expression
+//    types, such as `if` and `while` or `+` and `-`, will be handled identically in the printer
+//    and parser. So if all combinations of exprs involving `if` work correctly, then combinations
 //    using `while`, `if let`, and so on will likely work as well.
 
-
 #![feature(rustc_private)]
 
 extern crate rustc_data_structures;
@@ -155,9 +153,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
 }
 
 
-// Folders for manipulating the placement of `Paren` nodes.  See below for why this is needed.
+// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
 
-/// MutVisitor that removes all `ExprKind::Paren` nodes.
+/// `MutVisitor` that removes all `ExprKind::Paren` nodes.
 struct RemoveParens;
 
 impl MutVisitor for RemoveParens {
@@ -171,7 +169,7 @@ impl MutVisitor for RemoveParens {
 }
 
 
-/// MutVisitor that inserts `ExprKind::Paren` nodes around every `Expr`.
+/// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`.
 struct AddParens;
 
 impl MutVisitor for AddParens {
@@ -205,8 +203,8 @@ fn run() {
 
         // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
         // differences like placement of `Paren`s or the exact ranges of node spans.
-        // Unfortunately, there is no easy way to make this comparison.  Instead, we add `Paren`s
-        // everywhere we can, then pretty-print.  This should give an unambiguous representation of
+        // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
+        // everywhere we can, then pretty-print. This should give an unambiguous representation of
         // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
         // relying on the correctness of the very thing we're testing.
         RemoveParens.visit_expr(&mut e);
diff --git a/src/test/run-pass/traits/trait-object-auto-dedup.rs b/src/test/run-pass/traits/trait-object-auto-dedup.rs
index 98a386e4c6e1d..39d25eb7fe05b 100644
--- a/src/test/run-pass/traits/trait-object-auto-dedup.rs
+++ b/src/test/run-pass/traits/trait-object-auto-dedup.rs
@@ -1,14 +1,15 @@
 // run-pass
+
 #![allow(unused_assignments)]
+
 // Test that duplicate auto trait bounds in trait objects don't create new types.
 #[allow(unused_assignments)]
-
 use std::marker::Send as SendAlias;
 
 // A dummy trait for the non-auto trait.
 trait Trait {}
 
-// A dummy struct to implement Trait, Send, and .
+// A dummy struct to implement `Trait` and `Send`.
 struct Struct;
 
 impl Trait for Struct {}
@@ -23,12 +24,12 @@ impl dyn Trait + Send + Send {
 }
 
 fn main() {
-    // 1. Moving into a variable with more Sends and back.
+    // 1. Moving into a variable with more `Send`s and back.
     let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
     let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
     dyn_trait_send = dyn_trait_send_send;
 
-    // 2. Calling methods with different number of Sends.
+    // 2. Calling methods with different number of `Send`s.
     let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
     takes_dyn_trait_send_send(dyn_trait_send);
 
diff --git a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs
index 142f2f6d75169..04793c67b564d 100644
--- a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs
+++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs
@@ -9,7 +9,7 @@ mod boo {
     }
 }
 
-// don't actually know the type here
+// We don't actually know the type here.
 
 fn bomp2() {
     let _: &str = bomp(); //~ ERROR mismatched types
diff --git a/src/test/ui/type/type-alias-bounds.rs b/src/test/ui/type/type-alias-bounds.rs
index e2be2b9890251..f3cc5becc6f74 100644
--- a/src/test/ui/type/type-alias-bounds.rs
+++ b/src/test/ui/type/type-alias-bounds.rs
@@ -1,44 +1,44 @@
-// Test ignored_generic_bounds lint warning about bounds in type aliases
+// Test `ignored_generic_bounds` lint warning about bounds in type aliases.
 
 // compile-pass
 #![allow(dead_code)]
 
 use std::rc::Rc;
 
-type SVec<T: Send+Send> = Vec<T>;
+type SVec<T: Send + Send> = Vec<T>;
 //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
 type S2Vec<T> where T: Send = Vec<T>;
 //~^ WARN where clauses are not enforced in type aliases [type_alias_bounds]
-type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>);
+type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>);
 //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
-type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>);
+type WVec<'b, T: 'b + 'b> = (&'b u32, Vec<T>);
 //~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
 type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>);
 //~^ WARN where clauses are not enforced in type aliases [type_alias_bounds]
 
-static STATIC : u32 = 0;
+static STATIC: u32 = 0;
 
 fn foo<'a>(y: &'a i32) {
     // If any of the bounds above would matter, the code below would be rejected.
     // This can be seen when replacing the type aliases above by newtype structs.
     // (The type aliases have no unused parameters to make that a valid transformation.)
-    let mut x : SVec<_> = Vec::new();
+    let mut x: SVec<_> = Vec::new();
     x.push(Rc::new(42)); // is not send
 
-    let mut x : S2Vec<_> = Vec::new();
-    x.push(Rc::new(42)); // is not send
+    let mut x: S2Vec<_> = Vec::new();
+    x.push(Rc::new(42)); // is not `Send`
 
-    let mut x : VVec<'static, 'a> = (&STATIC, Vec::new());
-    x.1.push(y); // 'a: 'static does not hold
+    let mut x: VVec<'static, 'a> = (&STATIC, Vec::new());
+    x.1.push(y); // `'a: 'static` does not hold
 
-    let mut x : WVec<'static, &'a i32> = (&STATIC, Vec::new());
-    x.1.push(y); // &'a i32: 'static does not hold
+    let mut x: WVec<'static, &'a i32> = (&STATIC, Vec::new());
+    x.1.push(y); // `&'a i32: 'static` does not hold
 
-    let mut x : W2Vec<'static, &'a i32> = (&STATIC, Vec::new());
-    x.1.push(y); // &'a i32: 'static does not hold
+    let mut x: W2Vec<'static, &'a i32> = (&STATIC, Vec::new());
+    x.1.push(y); // `&'a i32: 'static` does not hold
 }
 
-// Bounds are not checked either, i.e., the definition is not necessarily well-formed
+// Bounds are not checked either; i.e., the definition is not necessarily well-formed.
 struct Sendable<T: Send>(T);
 type MySendable<T> = Sendable<T>; // no error here!
 
@@ -47,9 +47,9 @@ trait Bound { type Assoc; }
 type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
 type T2<U> where U: Bound = U::Assoc;  //~ WARN not enforced in type aliases
 
-// This errors
-// type T3<U> = U::Assoc;
-// Do this instead
+// This errors:
+// `type T3<U> = U::Assoc;`
+// Do this instead:
 type T4<U> = <U as Bound>::Assoc;
 
 // Make sure the help about associatd types is not shown incorrectly
diff --git a/src/test/ui/type/type-alias-bounds.stderr b/src/test/ui/type/type-alias-bounds.stderr
index 3cc844365fdd0..c0ff56d5ec038 100644
--- a/src/test/ui/type/type-alias-bounds.stderr
+++ b/src/test/ui/type/type-alias-bounds.stderr
@@ -1,8 +1,18 @@
+warning: duplicate auto trait `::marker[0]::Send[0]` found in type parameter bounds
+  --> $DIR/type-alias-bounds.rs:8:14
+   |
+LL | type SVec<T: Send + Send> = Vec<T>;
+   |              ^^^^   ^^^^ subsequent use of auto trait
+   |              |
+   |              first use of auto trait
+   |
+   = note: #[warn(duplicate_auto_traits_in_bounds)] on by default
+
 warning: bounds on generic parameters are not enforced in type aliases
   --> $DIR/type-alias-bounds.rs:8:14
    |
-LL | type SVec<T: Send+Send> = Vec<T>;
-   |              ^^^^ ^^^^
+LL | type SVec<T: Send + Send> = Vec<T>;
+   |              ^^^^   ^^^^
    |
    = note: #[warn(type_alias_bounds)] on by default
    = help: the bound will not be checked when the type alias is used, and should be removed
@@ -18,16 +28,16 @@ LL | type S2Vec<T> where T: Send = Vec<T>;
 warning: bounds on generic parameters are not enforced in type aliases
   --> $DIR/type-alias-bounds.rs:12:19
    |
-LL | type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>);
-   |                   ^^ ^^
+LL | type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>);
+   |                   ^^   ^^
    |
    = help: the bound will not be checked when the type alias is used, and should be removed
 
 warning: bounds on generic parameters are not enforced in type aliases
   --> $DIR/type-alias-bounds.rs:14:18
    |
-LL | type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>);
-   |                  ^^ ^^
+LL | type WVec<'b, T: 'b + 'b> = (&'b u32, Vec<T>);
+   |                  ^^   ^^
    |
    = help: the bound will not be checked when the type alias is used, and should be removed
 

From dce27cba78ebda2c5adfe149d33af5a88a28d08d Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Sun, 17 Mar 2019 15:26:01 +0000
Subject: [PATCH 02/24] Enabled `Self` in type aliases.

---
 src/librustc_resolve/lib.rs    | 12 +++++++++++-
 src/librustc_typeck/astconv.rs |  2 +-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index fb5c1b1953f08..61a860aef8597 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2529,7 +2529,17 @@ impl<'a> Resolver<'a> {
         debug!("(resolving item) resolving {} ({:?})", name, item.node);
 
         match item.node {
-            ItemKind::Ty(_, ref generics) |
+            ItemKind::Ty(_, ref generics) => {
+                self.with_current_self_item(item, |this| {
+                    this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                        let item_def_id = this.definitions.local_def_id(item.id);
+                        this.with_self_rib(Def::SelfTy(Some(item_def_id), None), |this| {
+                            visit::walk_item(this, item)
+                        })
+                    })
+                });
+            }
+
             ItemKind::Existential(_, ref generics) |
             ItemKind::Fn(_, _, ref generics, _) => {
                 self.with_generic_param_rib(
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 72ac041d2e57d..f6e3f1a99e831 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1770,7 +1770,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 tcx.mk_ty_param(index, tcx.hir().name_by_hir_id(hir_id).as_interned_str())
             }
             Res::SelfTy(Some(_), None) => {
-                // `Self` in trait.
+                // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(&path.segments);
                 tcx.mk_self_type()

From 3816958f18ea6c8990d64d03da839e5a180b0b9b Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Thu, 28 Feb 2019 22:43:53 +0000
Subject: [PATCH 03/24] Implemented for function bounds, type bounds, and named
 existential types.

---
 src/librustc/hir/lowering.rs           |  68 +++++++++-----
 src/librustc/hir/map/definitions.rs    |   5 ++
 src/librustc/hir/map/mod.rs            |  83 +++++++++++++----
 src/librustc/infer/opaque_types/mod.rs |  41 +++++----
 src/librustc/traits/select.rs          |   3 +-
 src/librustc_interface/util.rs         |  16 +++-
 src/librustc_passes/ast_validation.rs  |  18 ++--
 src/librustc_passes/hir_stats.rs       |   6 +-
 src/librustc_typeck/check/wfcheck.rs   | 118 ++++++++++++++-----------
 src/librustc_typeck/collect.rs         |  46 +++++++---
 src/libsyntax/ast.rs                   |  28 ++++--
 src/libsyntax/ext/build.rs             |  16 ++--
 src/libsyntax/mut_visit.rs             |  23 +++--
 src/libsyntax/parse/parser.rs          |  52 ++++++-----
 src/libsyntax/print/pprust.rs          |  15 +++-
 src/libsyntax/util/node_count.rs       |   4 +-
 src/libsyntax/visit.rs                 |  21 +++--
 17 files changed, 367 insertions(+), 196 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index af8c9c38de5ff..5a0e9d53b0833 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -69,7 +69,7 @@ use syntax::symbol::{kw, sym, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::visit::{self, Visitor};
-use syntax_pos::{edition, Span};
+use syntax_pos::{DUMMY_SP, edition, Span};
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -191,9 +191,9 @@ enum ImplTraitContext<'a> {
     /// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`.
     ///
     /// We optionally store a `DefId` for the parent item here so we can look up necessary
-    /// information later. It is `None` when no information about the context should be stored,
-    /// e.g., for consts and statics.
-    Existential(Option<DefId>),
+    /// information later. It is `None` when no information about the context should be stored
+    /// (e.g., for consts and statics).
+    Existential(Option<DefId> /* fn def-ID */),
 
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
@@ -216,7 +216,7 @@ impl<'a> ImplTraitContext<'a> {
         use self::ImplTraitContext::*;
         match self {
             Universal(params) => Universal(params),
-            Existential(did) => Existential(*did),
+            Existential(fn_def_id) => Existential(*fn_def_id),
             Disallowed(pos) => Disallowed(*pos),
         }
     }
@@ -1342,13 +1342,36 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_binding(&mut self, b: &TypeBinding,
-                        itctx: ImplTraitContext<'_>) -> hir::TypeBinding {
+    fn lower_assoc_ty_constraint(&mut self,
+                                 c: &AssocTyConstraint,
+                                 itctx: ImplTraitContext<'_>)
+                                 -> hir::TypeBinding {
+        let ty = match c.kind {
+            AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
+            AssocTyConstraintKind::Bound { ref bounds } => {
+                // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
+                let impl_ty_node_id = self.sess.next_node_id();
+                let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+                self.resolver.definitions().create_def_with_parent(
+                    parent_def_index,
+                    impl_ty_node_id,
+                    DefPathData::Misc,
+                    DefIndexAddressSpace::High,
+                    Mark::root(),
+                    DUMMY_SP);
+                self.lower_ty(&Ty {
+                    id: self.sess.next_node_id(),
+                    node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
+                    span: DUMMY_SP,
+                }, itctx)
+            }
+        };
+
         hir::TypeBinding {
-            hir_id: self.lower_node_id(b.id),
-            ident: b.ident,
-            ty: self.lower_ty(&b.ty, itctx),
-            span: b.span,
+            hir_id: self.lower_node_id(c.id),
+            ident: c.ident,
+            ty
+            span: c.span,
         }
     }
 
@@ -1604,7 +1627,7 @@ impl<'a> LoweringContext<'a> {
                 origin: hir::ExistTyOrigin::ReturnImplTrait,
             };
 
-            trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
+            trace!("exist ty from impl trait def-index: {:#?}", exist_ty_def_index);
             let exist_ty_id = lctx.generate_existential_type(
                 exist_ty_node_id,
                 exist_ty_item,
@@ -1617,7 +1640,7 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    /// Registers a new existential type with the proper NodeIds and
+    /// Registers a new existential type with the proper `NodeId`ss and
     /// returns the lowered node ID for the existential type.
     fn generate_existential_type(
         &mut self,
@@ -2195,7 +2218,7 @@ impl<'a> LoweringContext<'a> {
         param_mode: ParamMode,
         mut itctx: ImplTraitContext<'_>,
     ) -> (hir::GenericArgs, bool) {
-        let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
+        let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
         let has_types = args.iter().any(|arg| match arg {
             ast::GenericArg::Type(_) => true,
             _ => false,
@@ -2203,7 +2226,8 @@ impl<'a> LoweringContext<'a> {
         (
             hir::GenericArgs {
                 args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
-                bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
+                bindings: constraints.iter().map(
+                    |b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(),
                 parenthesized: false,
             },
             !has_types && param_mode == ParamMode::Optional
@@ -3236,12 +3260,14 @@ impl<'a> LoweringContext<'a> {
                 self.lower_ty(t, ImplTraitContext::disallowed()),
                 self.lower_generics(generics, ImplTraitContext::disallowed()),
             ),
-            ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
-                generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
-                bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
-                impl_trait_fn: None,
-                origin: hir::ExistTyOrigin::ExistentialType,
-            }),
+            ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
+                hir::ExistTy {
+                    generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
+                    bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)),
+                    impl_trait_fn: None,
+                    origin: hir::ExistTyOrigin::ExistentialType,
+                },
+            ),
             ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
                 hir::EnumDef {
                     variants: enum_definition
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index b85f6f6ce8483..b01eed8f6609d 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -397,6 +397,11 @@ impl Definitions {
         self.node_to_hir_id[node_id]
     }
 
+    #[inline]
+    pub fn def_index_to_node_id(&self, def_index: DefIndex) -> ast::NodeId {
+        self.as_local_node_id(DefId::local(def_index)).unwrap()
+    }
+
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists
     /// and it's not `DUMMY_SP`.
     #[inline]
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 18c596f164dc2..cdbeb8a4a545d 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -288,7 +288,7 @@ impl<'hir> Map<'hir> {
 
     #[inline]
     pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId {
-        self.definitions.as_local_node_id(DefId::local(def_index)).unwrap()
+        self.definitions.def_index_to_node_id(def_index)
     }
 
     #[inline]
@@ -649,16 +649,16 @@ impl<'hir> Map<'hir> {
         result
     }
 
-    /// Similar to `get_parent`; returns the parent node-id, or own `id` if there is
-    /// no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
-    /// present in the map -- so passing the return value of get_parent_node to
-    /// get may actually panic.
-    /// This function returns the immediate parent in the AST, whereas get_parent
+    /// Similar to `get_parent`; returns the parent node-ID, or just `hir_id` if there
+    /// is no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
+    /// present in the map, so passing the return value of `get_parent_node` to
+    /// `get` may in fact panic.
+    /// This function returns the immediate parent in the AST, whereas `get_parent`
     /// returns the enclosing item. Note that this might not be the actual parent
-    /// node in the AST - some kinds of nodes are not in the map and these will
-    /// never appear as the parent_node. So you can always walk the `parent_nodes`
-    /// from a node to the root of the ast (unless you get the same ID back here
-    /// that can happen if the ID is not in the map itself or is just weird).
+    /// node in the AST -- some kinds of nodes are not in the map and these will
+    /// never appear as the parent node. Thus, you can always walk the parent nodes
+    /// from a node to the root of the AST (unless you get back the same ID here,
+    /// which can happen if the ID is not in the map itself or is just weird).
     pub fn get_parent_node(&self, id: NodeId) -> NodeId {
         let hir_id = self.node_to_hir_id(id);
         let parent_hir_id = self.get_parent_node_by_hir_id(hir_id);
@@ -841,21 +841,66 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Returns the nearest enclosing scope. A scope is an item or block.
-    /// FIXME: it is not clear to me that all items qualify as scopes -- statics
-    /// and associated types probably shouldn't, for example. Behavior in this
-    /// regard should be expected to be highly unstable.
-    pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
+    /// Returns the nearest enclosing scope. A scope is roughly an item or block.
+    pub fn get_enclosing_scope(&self, id: HirId) -> Option<HirId> {
         self.walk_parent_nodes(hir_id, |node| match *node {
-            Node::Item(_) |
-            Node::ForeignItem(_) |
-            Node::TraitItem(_) |
-            Node::ImplItem(_) |
+            Node::Item(i) => {
+                match i.node {
+                    ItemKind::Fn(..)
+                    | ItemKind::Mod(..)
+                    | ItemKind::Enum(..)
+                    | ItemKind::Struct(..)
+                    | ItemKind::Union(..)
+                    | ItemKind::Trait(..)
+                    | ItemKind::Impl(..) => true,
+                    _ => false,
+                }
+            },
+            Node::ForeignItem(fi) => {
+                match fi.node {
+                    ForeignItemKind::Fn(..) => true,
+                    _ => false,
+                }
+            },
+            Node::TraitItem(ti) => {
+                match ti.node {
+                    TraitItemKind::Method(..) => true,
+                    _ => false,
+                }
+            },
+            Node::ImplItem(ii) => {
+                match ii.node {
+                    ImplItemKind::Method(..) => true,
+                    _ => false,
+                }
+            },
             Node::Block(_) => true,
             _ => false,
         }, |_| false).ok()
     }
 
+    /// Returns the defining scope for an existential type definition.
+    pub fn get_defining_scope(&self, id: NodeId) -> Option<NodeId> {
+        let mut scope = id;
+        loop {
+            scope = self.get_enclosing_scope(scope)?;
+            if scope == CRATE_NODE_ID {
+                return Some(CRATE_NODE_ID);
+            }
+            match self.get(scope) {
+                Node::Item(i) => {
+                    match i.node {
+                        ItemKind::Existential(ExistTy { impl_trait_fn: None, .. }) => {}
+                        _ => break,
+                    }
+                }
+                Node::Block(_) => {}
+                _ => break,
+            }
+        }
+        Some(scope)
+    }
+
     pub fn get_parent_did(&self, id: NodeId) -> DefId {
         let hir_id = self.node_to_hir_id(id);
         self.get_parent_did_by_hir_id(hir_id)
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 1423b855745e7..ef216110c9e62 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -786,13 +786,13 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             match tcx.hir().find_by_hir_id(opaque_hir_id)
                         {
                             Some(Node::Item(item)) => match item.node {
-                                // impl trait
+                                // Anonymous `impl Trait`
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: Some(parent),
                                     origin,
                                     ..
                                 }) => (parent == self.parent_def_id, origin),
-                                // named existential types
+                                // Named `existential type`
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: None,
                                     origin,
@@ -868,7 +868,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
 
         let predicates_of = tcx.predicates_of(def_id);
         debug!(
-            "instantiate_opaque_types: predicates: {:#?}",
+            "instantiate_opaque_types: predicates={:#?}",
             predicates_of,
         );
         let bounds = predicates_of.instantiate(tcx, substs);
@@ -884,11 +884,11 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         // (e.g., `existential type Foo<T: Bound>: Bar;` needs to be
         // defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
         debug!(
-            "instantiate_opaque_types: param_env: {:#?}",
+            "instantiate_opaque_types: param_env={:#?}",
             self.param_env,
         );
         debug!(
-            "instantiate_opaque_types: generics: {:#?}",
+            "instantiate_opaque_types: generics={:#?}",
             tcx.generics_of(def_id),
         );
 
@@ -922,8 +922,9 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
     }
 }
 
-/// Returns `true` if `opaque_node_id` is a sibling or a child of a sibling of `def_id`.
+/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
 ///
+/// Example:
 /// ```rust
 /// pub mod foo {
 ///     pub mod bar {
@@ -936,24 +937,28 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
 /// }
 /// ```
 ///
-/// Here, `def_id` is the `DefId` of the existential type `Baz` and `opaque_node_id` is the
-/// `NodeId` of the reference to `Baz` (i.e., the return type of both `f1` and `f2`).
-/// We return `true` if the reference is within the same module as the existential type
-/// (i.e., `true` for `f1`, `false` for `f2`).
+/// Here, `def_id` is the `DefId` of the defining use of the existential type (e.g., `f1` or `f2`),
+/// and `opaque_hir_id` is the `HirId` of the definition of the existential type `Baz`.
+/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
 pub fn may_define_existential_type(
     tcx: TyCtxt<'_, '_, '_>,
     def_id: DefId,
     opaque_hir_id: hir::HirId,
 ) -> bool {
     let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    // Named existential types can be defined by any siblings or
-    // children of siblings.
-    let mod_id = tcx.hir().get_parent_item(opaque_hir_id);
-    // We walk up the node tree until we hit the root or the parent
-    // of the opaque type.
-    while hir_id != mod_id && node_id != ast::CRATE_HIR_ID {
+    trace!(
+        "may_define_existential_type(def={:?}, opaque_node={:?})",
+        tcx.hir().get(hir_id),
+        tcx.hir().get(opaque_hir_id)
+    );
+
+    // Named existential types can be defined by any siblings or children of siblings.
+    let scope_id = tcx.hir().get_defining_scope(opaque_hir_id)
+                            .expect("could not get defining scope");
+    // We walk up the node tree until we hit the root or the scope of the opaque type.
+    while hir_id != scope_id && hir_id != ast::CRATE_hir_ID {
         hir_id = tcx.hir().get_parent_item(hir_id);
     }
-    // Syntactically we are allowed to define the concrete type.
-    hir_id == mod_id
+    // Syntactically, we are allowed to define the concrete type if:
+    hir_id == scope_id
 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index fc9756d52f55d..7810d65e88cc1 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1848,8 +1848,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             .iter()
             .filter_map(|o| o.to_opt_poly_trait_ref());
 
-        // micro-optimization: filter out predicates relating to different
-        // traits.
+        // Micro-optimization: filter out predicates relating to different traits.
         let matching_bounds =
             all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
 
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 4ff996d1f5707..f49f2110f2365 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -716,8 +716,22 @@ impl<'a> ReplaceBodyWithLoop<'a> {
                                     ast::GenericArg::Type(ty) => Some(ty),
                                     _ => None,
                                 });
+                                let any_assoc_ty_bounds = data.constraints.iter().any(|c| {
+                                    if let ast::AssocTyConstraintKind::Bound { .. } = c.kind {
+                                        true
+                                    } else {
+                                        false
+                                    }
+                                });
+                                any_assoc_ty_bounds ||
                                 any_involves_impl_trait(types.into_iter()) ||
-                                any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty))
+                                any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
+                                    if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind {
+                                        Some(ty)
+                                    } else {
+                                        None
+                                    }
+                                }))
                             },
                             Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter()) ||
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 6a17a84517e4a..2d602a7f1b468 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -93,14 +93,16 @@ impl<'a> AstValidator<'a> {
         self.outer_impl_trait = old;
     }
 
-    fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) {
-        // rust-lang/rust#57979: bug in old `visit_generic_args` called
-        // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
-        // if it happened to occur at `type_binding.ty`.
-        if let TyKind::ImplTrait(..) = type_binding.ty.node {
-            self.warning_period_57979_didnt_record_next_impl_trait = true;
+    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+        if let AssocTyConstraintKind::Equality { ref ty } = constraint.kind {
+            // rust-lang/rust#57979: bug in old `visit_generic_args` called
+            // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
+            // if it happened to occur at `ty`.
+            if let TyKind::ImplTrait(..) = ty.node {
+                self.warning_period_57979_didnt_record_next_impl_trait = true;
+            }
         }
-        self.visit_assoc_type_binding(type_binding);
+        self.visit_assoc_ty_constraint(constraint);
     }
 
     fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) {
@@ -724,7 +726,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
                 // are allowed to contain nested `impl Trait`.
                 self.with_impl_trait(None, |this| {
-                    walk_list!(this, visit_assoc_type_binding_from_generic_args, &data.bindings);
+                    walk_list!(this, visit_assoc_ty_constraint_from_generic_args, &data.constraints);
                 });
             }
             GenericArgs::Parenthesized(ref data) => {
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 0088c97679c66..6936aedb9de80 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -353,9 +353,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_type_binding(&mut self, type_binding: &'v ast::TypeBinding) {
-        self.record("TypeBinding", Id::None, type_binding);
-        ast_visit::walk_assoc_type_binding(self, type_binding)
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
+        self.record("AssocTyConstraint", Id::None, constraint);
+        ast_visit::walk_assoc_ty_constraint(self, constraint)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index e11172ae36d9b..2b627a692508e 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -20,8 +20,11 @@ use rustc::hir::itemlikevisit::ParItemLikeVisitor;
 use rustc::hir;
 
 /// Helper type of a temporary returned by `.for_item(...)`.
-/// Necessary because we can't write the following bound:
-/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`.
+/// This is necessary because we can't write the following bound:
+///
+/// ```rust
+/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)
+/// ```
 struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
     id: hir::HirId,
@@ -42,7 +45,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
             if !inh.tcx.features().trivial_bounds {
                 // As predicates are cached rather than obligations, this
                 // needsto be called first so that they are checked with an
-                // empty param_env.
+                // empty `param_env`.
                 check_false_global_bounds(&fcx, span, id);
             }
             let wf_tys = f(&fcx, fcx.tcx.global_tcx());
@@ -56,7 +59,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
 /// well-formed, meaning that they do not require any constraints not declared in the struct
 /// definition itself. For example, this definition would be illegal:
 ///
-///     struct Ref<'a, T> { x: &'a T }
+/// ```rust
+/// struct Ref<'a, T> { x: &'a T }
+/// ```
 ///
 /// because the type did not declare that `T:'a`.
 ///
@@ -75,7 +80,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
         // Right now we check that every default trait implementation
         // has an implementation of itself. Basically, a case like:
         //
-        // `impl Trait for T {}`
+        //     impl Trait for T {}
         //
         // has a requirement of `T: Trait` which was required for default
         // method implementations. Although this could be improved now that
@@ -85,7 +90,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
         // Since there's such a requirement, we need to check *just* positive
         // implementations, otherwise things like:
         //
-        // impl !Send for T {}
+        //     impl !Send for T {}
         //
         // won't be allowed unless there's an *explicit* implementation of `Send`
         // for `T`
@@ -98,7 +103,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
             if polarity == hir::ImplPolarity::Positive {
                 check_impl(tcx, item, self_ty, trait_ref);
             } else {
-                // FIXME(#27579) what amount of WF checking do we need for neg impls?
+                // FIXME(#27579): what amount of WF checking do we need for neg impls?
                 if trait_ref.is_some() && !is_auto {
                     span_err!(tcx.sess, item.span, E0192,
                               "negative impls are only allowed for \
@@ -302,7 +307,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         check_where_clauses(tcx, fcx, item.span, def_id, None);
 
-        vec![] // no implied bounds in a struct def'n
+        // No implied bounds in a struct definition.
+        vec![]
     });
 }
 
@@ -369,7 +375,8 @@ fn check_item_type<'a, 'tcx>(
             );
         }
 
-        vec![] // no implied bounds in a const etc
+        // No implied bounds in a const, etc.
+        vec![]
     });
 }
 
@@ -421,6 +428,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
     def_id: DefId,
     return_ty: Option<Ty<'tcx>>,
 ) {
+    debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty);
+
     let predicates = fcx.tcx.predicates_of(def_id);
     let generics = tcx.generics_of(def_id);
 
@@ -434,15 +443,17 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
     };
 
     // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
-    // For example this forbids the declaration:
-    // struct Foo<T = Vec<[u32]>> { .. }
-    // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+    // For example, this forbids the declaration:
+    //
+    //     struct Foo<T = Vec<[u32]>> { .. }
+    //
+    // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
     for param in &generics.params {
         if let GenericParamDefKind::Type { .. } = param.kind {
             if is_our_default(&param) {
                 let ty = fcx.tcx.type_of(param.def_id);
-                // ignore dependent defaults -- that is, where the default of one type
-                // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+                // Ignore dependent defaults -- that is, where the default of one type
+                // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                 // be sure if it will error or not as user might always specify the other.
                 if !ty.needs_subst() {
                     fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id),
@@ -468,16 +479,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
             }
 
             GenericParamDefKind::Type { .. } => {
-                // If the param has a default,
+                // If the param has a default, ...
                 if is_our_default(param) {
                     let default_ty = fcx.tcx.type_of(param.def_id);
-                    // and it's not a dependent default
+                    // ... and it's not a dependent default, ...
                     if !default_ty.needs_subst() {
-                        // then substitute with the default.
+                        // ... then substitute it with the default.
                         return default_ty.into();
                     }
                 }
-                // Mark unwanted params as err.
+                // Mark unwanted params as error.
                 fcx.tcx.types.err.into()
             }
 
@@ -525,7 +536,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
             Some(substituted_pred)
         }
     }).map(|pred| {
-        // convert each of those into an obligation. So if you have
+        // Convert each of those into an obligation. So if you have
         // something like `struct Foo<T: Copy = String>`, we would
         // take that predicate `T: Copy`, substitute to `String: Copy`
         // (actually that happens in the previous `flat_map` call),
@@ -595,14 +606,13 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
 /// ```rust
 /// existential type Foo<A, B>;
 ///
-/// // ok -- `Foo` is applied to two distinct, generic types.
+/// // Okay -- `Foo` is applied to two distinct, generic types.
 /// fn a<T, U>() -> Foo<T, U> { .. }
 ///
-/// // not ok -- `Foo` is applied to `T` twice.
+/// // Not okay -- `Foo` is applied to `T` twice.
 /// fn b<T>() -> Foo<T, T> { .. }
 ///
-///
-/// // not ok -- `Foo` is applied to a non-generic type.
+/// // Not okay -- `Foo` is applied to a non-generic type.
 /// fn b<T>() -> Foo<T, u32> { .. }
 /// ```
 ///
@@ -613,7 +623,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
     span: Span,
     ty: Ty<'tcx>,
 ) -> Vec<ty::Predicate<'tcx>> {
-    trace!("check_existential_types: {:?}", ty);
+    trace!("check_existential_types(ty={:?})", ty);
     let mut substituted_predicates = Vec::new();
     ty.fold_with(&mut ty::fold::BottomUpFolder {
         tcx: fcx.tcx,
@@ -621,17 +631,17 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
             if let ty::Opaque(def_id, substs) = ty.sty {
                 trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs);
                 let generics = tcx.generics_of(def_id);
-                // only check named existential types defined in this crate
+                // Only check named existential types defined in this crate.
                 if generics.parent.is_none() && def_id.is_local() {
                     let opaque_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
                     if may_define_existential_type(tcx, fn_def_id, opaque_hir_id) {
-                        trace!("check_existential_types may define. Generics: {:#?}", generics);
+                        trace!("check_existential_types: may define, generics={:#?}", generics);
                         let mut seen: FxHashMap<_, Vec<_>> = FxHashMap::default();
                         for (subst, param) in substs.iter().zip(&generics.params) {
                             match subst.unpack() {
                                 ty::subst::UnpackedKind::Type(ty) => match ty.sty {
                                     ty::Param(..) => {}
-                                    // prevent `fn foo() -> Foo<u32>` from being defining
+                                    // Prevent `fn foo() -> Foo<u32>` from being defining.
                                     _ => {
                                         tcx.sess
                                             .struct_span_err(
@@ -713,20 +723,19 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
                         }
                     } // if may_define_existential_type
 
-                    // now register the bounds on the parameters of the existential type
-                    // so the parameters given by the function need to fulfill them
-                    // ```rust
-                    // existential type Foo<T: Bar>: 'static;
-                    // fn foo<U>() -> Foo<U> { .. *}
-                    // ```
+                    // Now register the bounds on the parameters of the existential type
+                    // so the parameters given by the function need to fulfill them.
+                    //
+                    //     existential type Foo<T: Bar>: 'static;
+                    //     fn foo<U>() -> Foo<U> { .. *}
+                    //
                     // becomes
-                    // ```rust
-                    // existential type Foo<T: Bar>: 'static;
-                    // fn foo<U: Bar>() -> Foo<U> { .. *}
-                    // ```
+                    //
+                    //     existential type Foo<T: Bar>: 'static;
+                    //     fn foo<U: Bar>() -> Foo<U> { .. *}
                     let predicates = tcx.predicates_of(def_id);
                     trace!(
-                        "check_existential_types may define. adding predicates: {:#?}",
+                        "check_existential_types: may define, predicates={:#?}",
                         predicates,
                     );
                     for &(pred, _) in predicates.predicates.iter() {
@@ -751,7 +760,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                            method: &ty::AssocItem,
                                            self_ty: Ty<'tcx>)
 {
-    // check that the method has a valid receiver type, given the type `Self`
+    // Check that the method has a valid receiver type, given the type `Self`.
     debug!("check_method_receiver({:?}, self_ty={:?})",
            method, self_ty);
 
@@ -783,7 +792,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
 
     if fcx.tcx.features().arbitrary_self_types {
         if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
-            // report error, arbitrary_self_types was enabled
+            // Report error; `arbitrary_self_types` was enabled.
             fcx.tcx.sess.diagnostic().mut_span_err(
                 span, &format!("invalid method receiver type: {:?}", receiver_ty)
             ).note("type of `self` must be `Self` or a type that dereferences to it")
@@ -794,7 +803,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
     } else {
         if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
             if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
-                // report error, would have worked with arbitrary_self_types
+                // Report error; would have worked with `arbitrary_self_types`.
                 feature_gate::feature_err(
                     &fcx.tcx.sess.parse_sess,
                     sym::arbitrary_self_types,
@@ -808,7 +817,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                 ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
                 .emit();
             } else {
-                // report error, would not have worked with arbitrary_self_types
+                // Report error; would not have worked with `arbitrary_self_types`.
                 fcx.tcx.sess.diagnostic().mut_span_err(
                     span, &format!("invalid method receiver type: {:?}", receiver_ty)
                 ).note("type must be `Self` or a type that dereferences to it")
@@ -820,10 +829,11 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
     }
 }
 
-/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If
+/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
 /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
 /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
-/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref<Target=self_ty>`.
+/// strict: `receiver_ty` must implement `Receiver` and directly implement
+/// `Deref<Target = self_ty>`.
 ///
 /// N.B., there are cases this function returns `true` but causes an error to be emitted,
 /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
@@ -839,7 +849,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
 
     let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
 
-    // `self: Self` is always valid
+    // `self: Self` is always valid.
     if can_eq_self(receiver_ty) {
         if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
             err.emit();
@@ -849,15 +859,15 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
 
     let mut autoderef = fcx.autoderef(span, receiver_ty);
 
-    // the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`
+    // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
     if arbitrary_self_types_enabled {
         autoderef = autoderef.include_raw_pointers();
     }
 
-    // the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it.
+    // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
     autoderef.next();
 
-    // keep dereferencing `receiver_ty` until we get to `self_ty`
+    // Keep dereferencing `receiver_ty` until we get to `self_ty`.
     loop {
         if let Some((potential_self_ty, _)) = autoderef.next() {
             debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
@@ -882,14 +892,14 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
             return receiver_ty.references_error();
         }
 
-        // without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
-        // `self_ty`. Enforce this by only doing one iteration of the loop
+        // Without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
+        // `self_ty`. Enforce this by only doing one iteration of the loop.
         if !arbitrary_self_types_enabled {
             return false
         }
     }
 
-    // without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`
+    // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
     if !arbitrary_self_types_enabled {
         let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
             Some(did) => did,
@@ -968,7 +978,7 @@ fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut err = error_392(tcx, span, param_name);
 
     let suggested_marker_id = tcx.lang_items().phantom_data();
-    // help is available only in presence of lang items
+    // Help is available only in presence of lang items.
     if let Some(def_id) = suggested_marker_id {
         err.help(&format!("consider removing `{}` or using a marker such as `{}`",
                           param_name,
@@ -988,12 +998,12 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) {
     }).collect();
 
     for method_param in &generics.params {
-        // Shadowing is checked in resolve_lifetime.
+        // Shadowing is checked in `resolve_lifetime`.
         if let GenericParamDefKind::Lifetime = method_param.kind {
             continue
         }
         if impl_params.contains_key(&method_param.name) {
-            // Tighten up the span to focus on only the shadowing type
+            // Tighten up the span to focus on only the shadowing type.
             let type_span = tcx.def_span(method_param.def_id);
 
             // The expectation here is that the original trait declaration is
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f362263c16e75..ee7961197d3b0 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1488,10 +1488,13 @@ fn find_existential_constraints<'a, 'tcx>(
 
     impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
         fn check(&mut self, def_id: DefId) {
-            trace!("checking {:?}", def_id);
-            // don't try to check items that cannot possibly constrain the type
+            // Don't try to check items that cannot possibly constrain the type.
             if !self.tcx.has_typeck_tables(def_id) {
-                trace!("no typeck tables for {:?}", def_id);
+                debug!(
+                    "find_existential_constraints: no constraint for `{:?}` at `{:?}`: no tables",
+                    self.def_id,
+                    def_id,
+                );
                 return;
             }
             let ty = self
@@ -1500,7 +1503,14 @@ fn find_existential_constraints<'a, 'tcx>(
                 .concrete_existential_types
                 .get(&self.def_id);
             if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
-                // FIXME(oli-obk): trace the actual span from inference to improve errors
+                debug!(
+                    "find_existential_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
+                    self.def_id,
+                    def_id,
+                    ty,
+                );
+
+                // FIXME(oli-obk): trace the actual span from inference to improve errors.
                 let span = self.tcx.def_span(def_id);
                 // used to quickly look up the position of a generic parameter
                 let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
@@ -1555,14 +1565,15 @@ fn find_existential_constraints<'a, 'tcx>(
                     let mut ty = concrete_type.walk().fuse();
                     let mut p_ty = prev_ty.walk().fuse();
                     let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) {
-                        // type parameters are equal to any other type parameter for the purpose of
+                        // Type parameters are equal to any other type parameter for the purpose of
                         // concrete type equality, as it is possible to obtain the same type just
                         // by passing matching parameters to a function.
                         (ty::Param(_), ty::Param(_)) => true,
                         _ => t == p,
                     });
                     if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
-                        // found different concrete types for the existential type
+                        debug!("find_existential_constraints: span={:?}", span);
+                        // Found different concrete types for the existential type.
                         let mut err = self.tcx.sess.struct_span_err(
                             span,
                             "concrete type differs from previous defining existential type use",
@@ -1574,7 +1585,7 @@ fn find_existential_constraints<'a, 'tcx>(
                         err.span_note(prev_span, "previous use here");
                         err.emit();
                     } else if indices != *prev_indices {
-                        // found "same" concrete types, but the generic parameter order differs
+                        // Found "same" concrete types, but the generic parameter order differs.
                         let mut err = self.tcx.sess.struct_span_err(
                             span,
                             "concrete type's generic parameters differ from previous defining use",
@@ -1602,6 +1613,12 @@ fn find_existential_constraints<'a, 'tcx>(
                 } else {
                     self.found = Some((span, concrete_type, indices));
                 }
+            } else {
+                debug!(
+                    "find_existential_constraints: no constraint for `{:?}` at `{:?}`",
+                    self.def_id,
+                    def_id,
+                );
             }
         }
     }
@@ -1633,26 +1650,27 @@ fn find_existential_constraints<'a, 'tcx>(
         }
     }
 
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    let scope_id = tcx.hir().get_defining_scope(hir_id)
+                            .expect("could not get defining scope");
     let mut locator = ConstraintLocator {
         def_id,
         tcx,
         found: None,
     };
-    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    let parent = tcx.hir().get_parent_item(hir_id);
 
-    trace!("parent_id: {:?}", parent);
+    debug!("find_existential_constraints: scope_id={:?}", scope_id);
 
-    if parent == hir::CRATE_HIR_ID {
+    if scope_id == ast::CRATE_HIR_ID {
         intravisit::walk_crate(&mut locator, tcx.hir().krate());
     } else {
-        trace!("parent: {:?}", tcx.hir().get_by_hir_id(parent));
-        match tcx.hir().get_by_hir_id(parent) {
+        debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope_id));
+        match tcx.hir().get_by_hir_id(scope_id) {
             Node::Item(ref it) => intravisit::walk_item(&mut locator, it),
             Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
             Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
             other => bug!(
-                "{:?} is not a valid parent of an existential type item",
+                "{:?} is not a valid scope for an existential type item",
                 other
             ),
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 31e898048003d..598232f9f8f22 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -190,9 +190,9 @@ pub struct AngleBracketedArgs {
     pub span: Span,
     /// The arguments for this path segment.
     pub args: Vec<GenericArg>,
-    /// Bindings (equality constraints) on associated types, if present.
-    /// E.g., `Foo<A = Bar>`.
-    pub bindings: Vec<TypeBinding>,
+    /// Constraints on associated types, if any.
+    /// E.g., `Foo<A = Bar, B: Baz>`.
+    pub constraints: Vec<AssocTyConstraint>,
 }
 
 impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
@@ -225,7 +225,7 @@ impl ParenthesizedArgs {
         AngleBracketedArgs {
             span: self.span,
             args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(),
-            bindings: vec![],
+            constraints: vec![],
         }
     }
 }
@@ -1611,15 +1611,29 @@ impl fmt::Display for UintTy {
     }
 }
 
-// Bind a type to an associated type: `A = Foo`.
+/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct TypeBinding {
+pub struct AssocTyConstraint {
     pub id: NodeId,
     pub ident: Ident,
-    pub ty: P<Ty>,
+    pub kind: AssocTyConstraintKind,
     pub span: Span,
 }
 
+/// The kinds of an `AssocTyConstraint`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AssocTyConstraintKind {
+    /// E.g., `A = Bar` in `Foo<A = Bar>`.
+    Equality {
+        ty: P<Ty>,
+    },
+    /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
+    Bound {
+        bounds: GenericBounds,
+    },
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Ty {
     pub id: NodeId,
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 435a3d7b6a22a..2a03e49996b6c 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -18,7 +18,7 @@ pub trait AstBuilder {
                 global: bool,
                 idents: Vec<ast::Ident>,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding>)
+                constraints: Vec<ast::AssocTyConstraint>)
         -> ast::Path;
 
     fn qpath(&self, self_type: P<ast::Ty>,
@@ -29,7 +29,7 @@ pub trait AstBuilder {
                 trait_path: ast::Path,
                 ident: ast::Ident,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding>)
+                constraints: Vec<ast::AssocTyConstraint>)
                 -> (ast::QSelf, ast::Path);
 
     // types and consts
@@ -302,7 +302,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                 global: bool,
                 mut idents: Vec<ast::Ident> ,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding> )
+                constraints: Vec<ast::AssocTyConstraint> )
                 -> ast::Path {
         assert!(!idents.is_empty());
         let add_root = global && !idents[0].is_path_segment_keyword();
@@ -314,8 +314,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         segments.extend(idents.into_iter().map(|ident| {
             ast::PathSegment::from_ident(ident.with_span_pos(span))
         }));
-        let args = if !args.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedArgs { args, bindings, span }.into()
+        let args = if !args.is_empty() || !constraints.is_empty() {
+            ast::AngleBracketedArgs { args, constraints, span }.into()
         } else {
             None
         };
@@ -346,11 +346,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                  trait_path: ast::Path,
                  ident: ast::Ident,
                  args: Vec<ast::GenericArg>,
-                 bindings: Vec<ast::TypeBinding>)
+                 constraints: Vec<ast::AssocTyConstraint>)
                  -> (ast::QSelf, ast::Path) {
         let mut path = trait_path;
-        let args = if !args.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedArgs { args, bindings, span: ident.span }.into()
+        let args = if !args.is_empty() || !constraints.is_empty() {
+            ast::AngleBracketedArgs { args, constraints, span: ident.span }.into()
         } else {
             None
         };
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 757513098995b..fb1a7a680baaf 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -163,8 +163,8 @@ pub trait MutVisitor: Sized {
         noop_visit_lifetime(l, self);
     }
 
-    fn visit_ty_binding(&mut self, t: &mut TypeBinding) {
-        noop_visit_ty_binding(t, self);
+    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
+        noop_visit_ty_constraint(t, self);
     }
 
     fn visit_mod(&mut self, m: &mut Mod) {
@@ -400,11 +400,20 @@ pub fn noop_visit_guard<T: MutVisitor>(g: &mut Guard, vis: &mut T) {
     }
 }
 
-pub fn noop_visit_ty_binding<T: MutVisitor>(TypeBinding { id, ident, ty, span }: &mut TypeBinding,
-                                            vis: &mut T) {
+pub fn noop_visit_ty_constraint<T: MutVisitor>(
+    AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+    vis: &mut T
+) {
     vis.visit_id(id);
     vis.visit_ident(ident);
-    vis.visit_ty(ty);
+    match kind {
+        AssocTyConstraintKind::Equality { ref mut ty } => {
+            vis.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref mut bounds } => {
+            visit_bounds(bounds, vis);
+        }
+    }
     vis.visit_span(span);
 }
 
@@ -499,9 +508,9 @@ pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T)
 
 pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(data: &mut AngleBracketedArgs,
                                                                 vis: &mut T) {
-    let AngleBracketedArgs { args, bindings, span } = data;
+    let AngleBracketedArgs { args, constraints, span } = data;
     visit_vec(args, |arg| vis.visit_generic_arg(arg));
-    visit_vec(bindings, |binding| vis.visit_ty_binding(binding));
+    visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint));
     vis.visit_span(span);
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index abfce660c8041..790013f6eb128 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -27,7 +27,7 @@ use crate::ast::{VariantData, StructField};
 use crate::ast::StrStyle;
 use crate::ast::SelfKind;
 use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax};
-use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds};
+use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds};
 use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
 use crate::ast::{UseTree, UseTreeKind};
 use crate::ast::{BinOpKind, UnOp};
@@ -1791,11 +1791,11 @@ impl<'a> Parser<'a> {
             let lo = self.span;
             let args = if self.eat_lt() {
                 // `<'a, T, A = U>`
-                let (args, bindings) =
+                let (args, constraints) =
                     self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?;
                 self.expect_gt()?;
                 let span = lo.to(self.prev_span);
-                AngleBracketedArgs { args, bindings, span }.into()
+                AngleBracketedArgs { args, constraints, span }.into()
             } else {
                 // `(T, U) -> R`
                 self.bump(); // `(`
@@ -5076,7 +5076,7 @@ impl<'a> Parser<'a> {
         &mut self,
         style: PathStyle,
         lo: Span,
-    ) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
+    ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
         // We need to detect whether there are extra leading left angle brackets and produce an
         // appropriate error and suggestion. This cannot be implemented by looking ahead at
         // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
@@ -5211,11 +5211,11 @@ impl<'a> Parser<'a> {
 
     /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
     /// possibly including trailing comma.
-    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
+    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
         let mut args = Vec::new();
-        let mut bindings = Vec::new();
-        let mut misplaced_assoc_ty_bindings: Vec<Span> = Vec::new();
-        let mut assoc_ty_bindings: Vec<Span> = Vec::new();
+        let mut constraints = Vec::new();
+        let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
+        let mut assoc_ty_constraints: Vec<Span> = Vec::new();
 
         let args_lo = self.span;
 
@@ -5223,21 +5223,31 @@ impl<'a> Parser<'a> {
             if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
                 // Parse lifetime argument.
                 args.push(GenericArg::Lifetime(self.expect_lifetime()));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
-            } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
-                // Parse associated type binding.
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
+            } else if self.check_ident() && self.look_ahead(1,
+                    |t| t == &token::Eq || t == &token::Colon) {
+                // Parse associated type constraint.
                 let lo = self.span;
                 let ident = self.parse_ident()?;
-                self.bump();
-                let ty = self.parse_ty()?;
+                let kind = if self.eat(&token::Eq) {
+                    AssocTyConstraintKind::Equality {
+                        ty: self.parse_ty()?,
+                    }
+                } else if self.eat(&token::Colon) {
+                    AssocTyConstraintKind::Bound {
+                        bounds: self.parse_generic_bounds(Some(self.prev_span))?,
+                    }
+                } else {
+                    unreachable!();
+                };
                 let span = lo.to(self.prev_span);
-                bindings.push(TypeBinding {
+                constraints.push(AssocTyConstraint {
                     id: ast::DUMMY_NODE_ID,
                     ident,
-                    ty,
+                    kind,
                     span,
                 });
-                assoc_ty_bindings.push(span);
+                assoc_ty_constraints.push(span);
             } else if self.check_const_arg() {
                 // Parse const argument.
                 let expr = if let token::OpenDelim(token::Brace) = self.token {
@@ -5261,11 +5271,11 @@ impl<'a> Parser<'a> {
                     value: expr,
                 };
                 args.push(GenericArg::Const(value));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
             } else if self.check_type() {
                 // Parse type argument.
                 args.push(GenericArg::Type(self.parse_ty()?));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
             } else {
                 break
             }
@@ -5278,12 +5288,12 @@ impl<'a> Parser<'a> {
         // FIXME: we would like to report this in ast_validation instead, but we currently do not
         // preserve ordering of generic parameters with respect to associated type binding, so we
         // lose that information after parsing.
-        if misplaced_assoc_ty_bindings.len() > 0 {
+        if misplaced_assoc_ty_constraints.len() > 0 {
             let mut err = self.struct_span_err(
                 args_lo.to(self.prev_span),
                 "associated type bindings must be declared after generic parameters",
             );
-            for span in misplaced_assoc_ty_bindings {
+            for span in misplaced_assoc_ty_constraints {
                 err.span_label(
                     span,
                     "this associated type binding should be moved after the generic parameters",
@@ -5292,7 +5302,7 @@ impl<'a> Parser<'a> {
             err.emit();
         }
 
-        Ok((args, bindings))
+        Ok((args, constraints))
     }
 
     /// Parses an optional where-clause and places it in `generics`.
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 44e1f5398d3e0..57c01e9e3efea 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2450,14 +2450,21 @@ impl<'a> State<'a> {
 
                 let mut comma = data.args.len() != 0;
 
-                for binding in data.bindings.iter() {
+                for constraint in data.constraints.iter() {
                     if comma {
                         self.word_space(",")?
                     }
-                    self.print_ident(binding.ident)?;
+                    self.print_ident(constraint.ident)?;
                     self.s.space()?;
-                    self.word_space("=")?;
-                    self.print_type(&binding.ty)?;
+                    match constraint.kind {
+                        ast::AssocTyConstraintKind::Equality { ref ty } => {
+                            self.word_space("=")?;
+                            self.print_type(ty)?;
+                        }
+                        ast::AssocTyConstraintKind::Bound { ref bounds } => {
+                            self.print_type_bounds(":", &*bounds)?;
+                        }
+                    }
                     comma = true;
                 }
 
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index 521edac8f5fc3..f17eb3b39432e 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -131,9 +131,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_generic_args(self, path_span, generic_args)
     }
-    fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
+    fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
         self.count += 1;
-        walk_assoc_type_binding(self, type_binding)
+        walk_assoc_ty_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, _attr: &Attribute) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index ba57055b8e009..334709b152197 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -139,8 +139,8 @@ pub trait Visitor<'ast>: Sized {
             GenericArg::Const(ct) => self.visit_anon_const(ct),
         }
     }
-    fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) {
-        walk_assoc_type_binding(self, type_binding)
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
+        walk_assoc_ty_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, attr: &'ast Attribute) {
         walk_attribute(self, attr)
@@ -404,7 +404,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
     match *generic_args {
         GenericArgs::AngleBracketed(ref data) => {
             walk_list!(visitor, visit_generic_arg, &data.args);
-            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
+            walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints);
         }
         GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
@@ -413,10 +413,17 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
     }
 }
 
-pub fn walk_assoc_type_binding<'a, V: Visitor<'a>>(visitor: &mut V,
-                                                   type_binding: &'a TypeBinding) {
-    visitor.visit_ident(type_binding.ident);
-    visitor.visit_ty(&type_binding.ty);
+pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V,
+                                                    constraint: &'a AssocTyConstraint) {
+    visitor.visit_ident(constraint.ident);
+    match constraint.kind {
+        AssocTyConstraintKind::Equality { ref ty } => {
+            visitor.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref bounds } => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
 }
 
 pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {

From aaa53ec8531565e2f5721548b5a38c0062aa0e51 Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Sat, 16 Mar 2019 00:04:02 +0000
Subject: [PATCH 04/24] Implemented for traits (associated type definitions).

---
 src/librustc/hir/intravisit.rs         |   3 +
 src/librustc/hir/lowering.rs           |  54 +++--
 src/librustc/hir/mod.rs                |   2 +
 src/librustc/hir/print.rs              |   3 +
 src/librustc/infer/opaque_types/mod.rs |  12 +-
 src/librustc_interface/util.rs         |   3 +-
 src/librustc_privacy/lib.rs            |   5 +-
 src/librustc_typeck/astconv.rs         | 289 +++++++++++++++++++------
 src/librustc_typeck/check/regionck.rs  |   4 +-
 src/librustc_typeck/collect.rs         | 172 +++------------
 src/librustc_typeck/lib.rs             |  11 +-
 src/librustdoc/clean/mod.rs            |   5 +-
 12 files changed, 313 insertions(+), 250 deletions(-)

diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index f838ec84d8b31..da4d41c9d872f 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -626,6 +626,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyKind::CVarArgs(ref lt) => {
             visitor.visit_lifetime(lt)
         }
+        TyKind::AssocTyExistential(ref bounds) => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
         TyKind::Infer | TyKind::Err => {}
     }
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 5a0e9d53b0833..2c2cd6a2f6f53 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -195,6 +195,12 @@ enum ImplTraitContext<'a> {
     /// (e.g., for consts and statics).
     Existential(Option<DefId> /* fn def-ID */),
 
+    /// Treat `impl Trait` as a bound on the associated type applied to the trait.
+    /// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
+    /// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
+    /// { type Bar: Iterator; }`.
+    AssociatedTy,
+
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -217,6 +223,7 @@ impl<'a> ImplTraitContext<'a> {
         match self {
             Universal(params) => Universal(params),
             Existential(fn_def_id) => Existential(*fn_def_id),
+            AssociatedTy => AssociatedTy,
             Disallowed(pos) => Disallowed(*pos),
         }
     }
@@ -1537,6 +1544,16 @@ impl<'a> LoweringContext<'a> {
                             }),
                         ))
                     }
+                    ImplTraitContext::AssociatedTy => {
+                        let hir_bounds = self.lower_param_bounds(
+                            bounds,
+                            ImplTraitContext::AssociatedTy,
+                        );
+
+                        hir::TyKind::AssocTyExistential(
+                            hir_bounds,
+                        )
+                    }
                     ImplTraitContext::Disallowed(pos) => {
                         let allowed_in = if self.sess.features_untracked()
                                                 .impl_trait_in_bindings {
@@ -1640,8 +1657,8 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    /// Registers a new existential type with the proper `NodeId`ss and
-    /// returns the lowered node ID for the existential type.
+    /// Registers a new existential type with the proper `NodeId`s and
+    /// returns the lowered node-ID for the existential type.
     fn generate_existential_type(
         &mut self,
         exist_ty_node_id: NodeId,
@@ -2226,8 +2243,9 @@ impl<'a> LoweringContext<'a> {
         (
             hir::GenericArgs {
                 args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
-                bindings: constraints.iter().map(
-                    |b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(),
+                bindings: constraints.iter()
+                    .map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow()))
+                    .collect(),
                 parenthesized: false,
             },
             !has_types && param_mode == ParamMode::Optional
@@ -3257,13 +3275,13 @@ impl<'a> LoweringContext<'a> {
             ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
             ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
             ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
-                self.lower_ty(t, ImplTraitContext::disallowed()),
-                self.lower_generics(generics, ImplTraitContext::disallowed()),
+                self.lower_ty(t, ImplTraitContext::AssociatedTy),
+                self.lower_generics(generics, ImplTraitContext::AssociatedTy),
             ),
             ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
                 hir::ExistTy {
-                    generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
-                    bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)),
+                    generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+                    bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
                     impl_trait_fn: None,
                     origin: hir::ExistTyOrigin::ExistentialType,
                 },
@@ -3276,20 +3294,20 @@ impl<'a> LoweringContext<'a> {
                         .map(|x| self.lower_variant(x))
                         .collect(),
                 },
-                self.lower_generics(generics, ImplTraitContext::disallowed()),
+                self.lower_generics(generics, ImplTraitContext::AssociatedTy),
             ),
             ItemKind::Struct(ref struct_def, ref generics) => {
                 let struct_def = self.lower_variant_data(struct_def);
                 hir::ItemKind::Struct(
                     struct_def,
-                    self.lower_generics(generics, ImplTraitContext::disallowed()),
+                    self.lower_generics(generics, ImplTraitContext::AssociatedTy),
                 )
             }
             ItemKind::Union(ref vdata, ref generics) => {
                 let vdata = self.lower_variant_data(vdata);
                 hir::ItemKind::Union(
                     vdata,
-                    self.lower_generics(generics, ImplTraitContext::disallowed()),
+                    self.lower_generics(generics, ImplTraitContext::AssociatedTy),
                 )
             }
             ItemKind::Impl(
@@ -3656,15 +3674,17 @@ impl<'a> LoweringContext<'a> {
                 );
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
             }
-            TraitItemKind::Type(ref bounds, ref default) => (
-                self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
-                hir::TraitItemKind::Type(
-                    self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
+            TraitItemKind::Type(ref bounds, ref default) => {
+                let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
+                let node = hir::TraitItemKind::Type(
+                    self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
                     default
                         .as_ref()
                         .map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
-                ),
-            ),
+                );
+
+                (generics, node)
+            },
             TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
         };
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index e29998db7778f..20968ec6a63be 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1898,6 +1898,8 @@ pub enum TyKind {
     /// Placeholder for C-variadic arguments. We "spoof" the `VaList` created
     /// from the variadic arguments. This type is only valid up to typeck.
     CVarArgs(Lifetime),
+    /// The existential type (i.e., `impl Trait`) that constrains an associated type.
+    AssocTyExistential(HirVec<GenericBound>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 709a43c4734c1..c8f9e4c7043e0 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -409,6 +409,9 @@ impl<'a> State<'a> {
             hir::TyKind::CVarArgs(_) => {
                 self.s.word("...")?;
             }
+            hir::TyKind::AssocTyExistential(ref bounds) => {
+                self.print_bounds(":", bounds)?;
+            }
         }
         self.end()
     }
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index ef216110c9e62..2127fbbd56e93 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -948,15 +948,17 @@ pub fn may_define_existential_type(
     let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
     trace!(
         "may_define_existential_type(def={:?}, opaque_node={:?})",
-        tcx.hir().get(hir_id),
-        tcx.hir().get(opaque_hir_id)
+        tcx.hir().get_by_hir_id(hir_id),
+        tcx.hir().get_by_hir_id(opaque_hir_id)
     );
 
     // Named existential types can be defined by any siblings or children of siblings.
-    let scope_id = tcx.hir().get_defining_scope(opaque_hir_id)
-                            .expect("could not get defining scope");
+    let scope_node_id = tcx.hir()
+        .get_defining_scope(tcx.hir().hir_to_node_id(opaque_hir_id))
+        .expect("could not get defining scope");
+    let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
     // We walk up the node tree until we hit the root or the scope of the opaque type.
-    while hir_id != scope_id && hir_id != ast::CRATE_hir_ID {
+    while hir_id != scope_id && hir_id != hir::CRATE_HIR_ID {
         hir_id = tcx.hir().get_parent_item(hir_id);
     }
     // Syntactically, we are allowed to define the concrete type if:
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index f49f2110f2365..fe24eab9f4439 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -726,7 +726,8 @@ impl<'a> ReplaceBodyWithLoop<'a> {
                                 any_assoc_ty_bounds ||
                                 any_involves_impl_trait(types.into_iter()) ||
                                 any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
-                                    if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind {
+                                    if let ast::AssocTyConstraintKind::Equality { ref ty }
+                                            = c.kind {
                                         Some(ty)
                                     } else {
                                         None
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index f084d3b9f28c3..6d01328cd16e6 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1040,12 +1040,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
         if !self.in_body {
             // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
             // The traits' privacy in bodies is already checked as a part of trait object types.
-            let (principal, projections) =
-                rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
+            let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
             if self.visit_trait(*principal.skip_binder()) {
                 return;
             }
-            for (poly_predicate, _) in projections {
+            for (poly_predicate, _) in bounds.projection_bounds {
                 let tcx = self.tcx;
                 if self.visit(poly_predicate.skip_binder().ty) ||
                    self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index f6e3f1a99e831..6123ee2af6e88 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -8,6 +8,7 @@ use crate::hir::def::{CtorOf, Res, DefKind};
 use crate::hir::def_id::DefId;
 use crate::hir::HirVec;
 use crate::lint;
+use crate::middle::lang_items::SizedTraitLangItem;
 use crate::middle::resolve_lifetime as rl;
 use crate::namespace::Namespace;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -86,12 +87,22 @@ pub trait AstConv<'gcx, 'tcx> {
     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
 }
 
+pub enum SizedByDefault {
+    Yes,
+    No,
+}
+
 struct ConvertedBinding<'tcx> {
     item_name: ast::Ident,
-    ty: Ty<'tcx>,
+    kind: ConvertedBindingKind<'tcx>,
     span: Span,
 }
 
+enum ConvertedBindingKind<'tcx> {
+    Equality(Ty<'tcx>),
+    Constraint(P<[hir::GenericBound]>),
+}
+
 #[derive(PartialEq)]
 enum GenericArgPosition {
     Type,
@@ -562,10 +573,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     /// set of substitutions. This may involve applying defaulted type parameters.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
-    fn create_substs_for_ast_path(&self,
+    fn create_substs_for_ast_path<'a>(&self,
         span: Span,
         def_id: DefId,
-        generic_args: &hir::GenericArgs,
+        generic_args: &'a hir::GenericArgs,
         infer_types: bool,
         self_ty: Option<Ty<'tcx>>)
         -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'tcx>>, Option<Vec<Span>>)
@@ -688,13 +699,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             },
         );
 
-        let assoc_bindings = generic_args.bindings.iter().map(|binding| {
-            ConvertedBinding {
-                item_name: binding.ident,
-                ty: self.ast_ty_to_ty(&binding.ty),
-                span: binding.span,
-            }
-        }).collect();
+        let assoc_bindings = generic_args.bindings.iter()
+            .map(|binding| {
+                let kind = if let hir::TyKind::AssocTyExistential(ref bounds) = binding.ty.node {
+                    ConvertedBindingKind::Constraint(bounds.clone())
+                } else {
+                    ConvertedBindingKind::Equality(self.ast_ty_to_ty(&binding.ty))
+                };
+                ConvertedBinding {
+                    item_name: binding.ident,
+                    kind,
+                    span: binding.span,
+                }
+            })
+            .collect();
 
         debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
                generic_params, self_ty, substs);
@@ -725,7 +743,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     pub(super) fn instantiate_poly_trait_ref_inner(&self,
         trait_ref: &hir::TraitRef,
         self_ty: Ty<'tcx>,
-        poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+        bounds: &mut Bounds<'tcx>,
         speculative: bool,
     ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
     {
@@ -744,36 +762,40 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
 
         let mut dup_bindings = FxHashMap::default();
-        poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
-            // specify type to assert that error was already reported in Err case:
-            let predicate: Result<_, ErrorReported> =
-                self.ast_type_binding_to_poly_projection_predicate(
-                    trait_ref.hir_ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
-            // okay to ignore Err because of ErrorReported (see above)
-            Some((predicate.ok()?, binding.span))
-        }));
-
-        debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
-               trait_ref, poly_projections, poly_trait_ref);
+        for binding in &assoc_bindings {
+            // Specify type to assert that error was already reported in `Err` case.
+            let _ =
+                self.add_predicates_for_ast_type_binding(
+                    trait_ref.hir_ref_id,
+                    poly_trait_ref,
+                    binding,
+                    bounds,
+                    speculative,
+                    &mut dup_bindings
+                );
+            // Okay to ignore `Err` because of `ErrorReported` (see above).
+        }
+
+        debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
+               trait_ref, bounds, poly_trait_ref);
         (poly_trait_ref, potential_assoc_types)
     }
 
     pub fn instantiate_poly_trait_ref(&self,
         poly_trait_ref: &hir::PolyTraitRef,
         self_ty: Ty<'tcx>,
-        poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>)
-        -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
+        bounds: &mut Bounds<'tcx>
+    ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
     {
-        self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty,
-                                              poly_projections, false)
+        self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false)
     }
 
     fn ast_path_to_mono_trait_ref(&self,
-                                  span: Span,
-                                  trait_def_id: DefId,
-                                  self_ty: Ty<'tcx>,
-                                  trait_segment: &hir::PathSegment)
-                                  -> ty::TraitRef<'tcx>
+        span: Span,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        trait_segment: &hir::PathSegment
+    ) -> ty::TraitRef<'tcx>
     {
         let (substs, assoc_bindings, _) =
             self.create_substs_for_ast_trait_ref(span,
@@ -830,15 +852,120 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         })
     }
 
-    fn ast_type_binding_to_poly_projection_predicate(
+    // Returns `true` if a bounds list includes `?Sized`.
+    pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound], span: Span) -> bool {
+        let tcx = self.tcx();
+
+        // Try to find an unbound in bounds.
+        let mut unbound = None;
+        for ab in ast_bounds {
+            if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
+                if unbound.is_none() {
+                    unbound = Some(ptr.trait_ref.clone());
+                } else {
+                    span_err!(
+                        tcx.sess,
+                        span,
+                        E0203,
+                        "type parameter has more than one relaxed default \
+                        bound, only one is supported"
+                    );
+                }
+            }
+        }
+
+        let kind_id = tcx.lang_items().require(SizedTraitLangItem);
+        match unbound {
+            Some(ref tpb) => {
+                // FIXME(#8559) currently requires the unbound to be built-in.
+                if let Ok(kind_id) = kind_id {
+                    if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
+                        tcx.sess.span_warn(
+                            span,
+                            "default bound relaxed for a type parameter, but \
+                            this does nothing because the given bound is not \
+                            a default. Only `?Sized` is supported",
+                        );
+                    }
+                }
+            }
+            _ if kind_id.is_ok() => {
+                return false;
+            }
+            // No lang item for `Sized`, so we can't add it as a bound.
+            None => {}
+        }
+
+        true
+    }
+
+    pub fn add_bounds(&self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[hir::GenericBound],
+        bounds: &mut Bounds<'tcx>,
+    ) {
+        let mut trait_bounds = Vec::new();
+        let mut region_bounds = Vec::new();
+
+        for ast_bound in ast_bounds {
+            match *ast_bound {
+                hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) =>
+                    trait_bounds.push(b),
+                hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
+                hir::GenericBound::Outlives(ref l) =>
+                    region_bounds.push(l),
+            }
+        }
+
+        for bound in trait_bounds {
+            let (poly_trait_ref, _) = self.instantiate_poly_trait_ref(
+                bound,
+                param_ty,
+                bounds,
+            );
+            bounds.trait_bounds.push((poly_trait_ref, bound.span))
+        }
+
+        bounds.region_bounds.extend(region_bounds
+            .into_iter()
+            .map(|r| (self.ast_region_to_region(r, None), r.span))
+        );
+
+        bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
+    }
+
+    /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
+    /// or a region) to ty's notion of ty param bounds, which can either be user-defined traits or the
+    /// built-in trait `Send`.
+    pub fn compute_bounds(&self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[hir::GenericBound],
+        sized_by_default: SizedByDefault,
+        span: Span,
+    ) -> Bounds<'tcx> {
+        let mut bounds = Bounds::default();
+        self.add_bounds(param_ty, ast_bounds, &mut bounds);
+        bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
+            if !self.is_unsized(ast_bounds, span) {
+                Some(span)
+            } else {
+                None
+            }
+        } else {
+            None
+        };
+        bounds
+    }
+
+    fn add_predicates_for_ast_type_binding(
         &self,
         hir_ref_id: hir::HirId,
         trait_ref: ty::PolyTraitRef<'tcx>,
         binding: &ConvertedBinding<'tcx>,
+        bounds: &mut Bounds<'tcx>,
         speculative: bool,
-        dup_bindings: &mut FxHashMap<DefId, Span>)
-        -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
-    {
+        dup_bindings: &mut FxHashMap<DefId, Span>,
+    ) -> Result<(), ErrorReported> {
         let tcx = self.tcx();
 
         if !speculative {
@@ -865,28 +992,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             //
             //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
             //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-            let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
-            let late_bound_in_ty =
-                tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(binding.ty));
-            debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
-            debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
-            for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
-                let br_name = match *br {
-                    ty::BrNamed(_, name) => name,
-                    _ => {
-                        span_bug!(
-                            binding.span,
-                            "anonymous bound region {:?} in binding but not trait ref",
-                            br);
-                    }
-                };
-                struct_span_err!(tcx.sess,
+            if let ConvertedBindingKind::Equality(ty) = binding.kind {
+                let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
+                let late_bound_in_ty =
+                    tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
+                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+                for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
+                    let br_name = match *br {
+                        ty::BrNamed(_, name) => name,
+                        _ => {
+                            span_bug!(
                                 binding.span,
-                                E0582,
-                                "binding for associated type `{}` references lifetime `{}`, \
-                                 which does not appear in the trait input types",
-                                binding.item_name, br_name)
-                    .emit();
+                                "anonymous bound region {:?} in binding but not trait ref",
+                                br);
+                        }
+                    };
+                    struct_span_err!(tcx.sess,
+                                    binding.span,
+                                    E0582,
+                                    "binding for associated type `{}` references lifetime `{}`, \
+                                     which does not appear in the trait input types",
+                                    binding.item_name, br_name)
+                        .emit();
+                }
             }
         }
 
@@ -931,16 +1060,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 .or_insert(binding.span);
         }
 
-        Ok(candidate.map_bound(|trait_ref| {
-            ty::ProjectionPredicate {
-                projection_ty: ty::ProjectionTy::from_ref_and_name(
-                    tcx,
-                    trait_ref,
-                    binding.item_name,
-                ),
-                ty: binding.ty,
+        match binding.kind {
+            ConvertedBindingKind::Equality(ref ty) => {
+                bounds.projection_bounds.push((candidate.map_bound(|trait_ref| {
+                    ty::ProjectionPredicate {
+                        projection_ty: ty::ProjectionTy::from_ref_and_name(
+                            tcx,
+                            trait_ref,
+                            binding.item_name,
+                        ),
+                        ty,
+                    }
+                }), binding.span));
             }
-        }))
+            ConvertedBindingKind::Constraint(ref ast_bounds) => {
+                self.add_bounds(
+                    trait_ref.self_ty(),
+                    ast_bounds,
+                    bounds,
+                );
+            }
+        }
+        Ok(())
     }
 
     fn ast_path_to_ty(&self,
@@ -974,7 +1115,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     {
         let tcx = self.tcx();
 
-        let mut projection_bounds = Vec::new();
+        let mut bounds = Bounds::default();
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
         // FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
@@ -986,7 +1127,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
                     trait_bound,
                     dummy_self,
-                    &mut projection_bounds
+                    &mut bounds,
                 );
                 potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
                 (trait_ref, trait_bound.span)
@@ -1074,14 +1215,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     // which is uglier but works. See the discussion in #56288 for alternatives.
                     if !references_self {
                         // Include projections defined on supertraits.
-                        projection_bounds.push((pred, DUMMY_SP))
+                        bounds.projection_bounds.push((pred, DUMMY_SP))
                     }
                 }
                 _ => ()
             }
         }
 
-        for (projection_bound, _) in &projection_bounds {
+        for (projection_bound, _) in &bounds.projection_bounds {
             associated_types.remove(&projection_bound.projection_def_id());
         }
 
@@ -1161,7 +1302,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let existential_trait_refs = regular_traits.iter().map(|i| {
             i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
         });
-        let existential_projections = projection_bounds.iter().map(|(bound, _)| {
+        let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
                 let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
                 ty::ExistentialProjection {
@@ -1900,6 +2041,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 let region = self.ast_region_to_region(&lt, None);
                 tcx.type_of(va_list_did).subst(tcx, &[region.into()])
             }
+            hir::TyKind::AssocTyExistential(..) => {
+                // Type is never actually used.
+                tcx.types.err
+            }
             hir::TyKind::Err => {
                 tcx.types.err
             }
@@ -2121,12 +2266,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
 
 // A helper struct for conveniently grouping a set of bounds which we pass to
 // and return from functions in multiple places.
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
     pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,
-    pub implicitly_sized: Option<Span>,
     pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
     pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+    pub implicitly_sized: Option<Span>,
 }
 
 impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 21d7e483e9d15..c3b6fb21e38d6 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -991,8 +991,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
-    /// adjustments) are valid for at least `minimum_lifetime`
+    /// Guarantees that any lifetimes that appear in the type of the node `id` (after applying
+    /// adjustments) are valid for at least `minimum_lifetime`.
     fn type_of_node_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ee7961197d3b0..92d0e37cb9bbd 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -14,11 +14,10 @@
 //! At present, however, we do run collection across all items in the
 //! crate as a kind of pass. This should eventually be factored away.
 
-use crate::astconv::{AstConv, Bounds};
+use crate::astconv::{AstConv, Bounds, SizedByDefault};
 use crate::constrained_generic_params as cgp;
 use crate::check::intrinsic::intrisic_operation_unsafety;
 use crate::lint;
-use crate::middle::lang_items::SizedTraitLangItem;
 use crate::middle::resolve_lifetime as rl;
 use crate::middle::weak_lang_items;
 use rustc::mir::mono::Linkage;
@@ -704,7 +703,7 @@ fn super_predicates_of<'a, 'tcx>(
 
     // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
     let self_param_ty = tcx.mk_self_type();
-    let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
+    let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
 
     let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
@@ -1650,9 +1649,11 @@ fn find_existential_constraints<'a, 'tcx>(
         }
     }
 
-    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    let scope_id = tcx.hir().get_defining_scope(hir_id)
-                            .expect("could not get defining scope");
+    let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
+    let scope_node_id = tcx.hir()
+        .get_defining_scope(node_id)
+        .expect("could not get defining scope");
+    let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
     let mut locator = ConstraintLocator {
         def_id,
         tcx,
@@ -1661,7 +1662,7 @@ fn find_existential_constraints<'a, 'tcx>(
 
     debug!("find_existential_constraints: scope_id={:?}", scope_id);
 
-    if scope_id == ast::CRATE_HIR_ID {
+    if scope_id == hir::CRATE_HIR_ID {
         intravisit::walk_crate(&mut locator, tcx.hir().krate());
     } else {
         debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope_id));
@@ -1788,57 +1789,6 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> hir::I
     }
 }
 
-// Is it marked with ?Sized
-fn is_unsized<'gcx: 'tcx, 'tcx>(
-    astconv: &dyn AstConv<'gcx, 'tcx>,
-    ast_bounds: &[hir::GenericBound],
-    span: Span,
-) -> bool {
-    let tcx = astconv.tcx();
-
-    // Try to find an unbound in bounds.
-    let mut unbound = None;
-    for ab in ast_bounds {
-        if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
-            if unbound.is_none() {
-                unbound = Some(ptr.trait_ref.clone());
-            } else {
-                span_err!(
-                    tcx.sess,
-                    span,
-                    E0203,
-                    "type parameter has more than one relaxed default \
-                     bound, only one is supported"
-                );
-            }
-        }
-    }
-
-    let kind_id = tcx.lang_items().require(SizedTraitLangItem);
-    match unbound {
-        Some(ref tpb) => {
-            // FIXME(#8559) currently requires the unbound to be built-in.
-            if let Ok(kind_id) = kind_id {
-                if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
-                    tcx.sess.span_warn(
-                        span,
-                        "default bound relaxed for a type parameter, but \
-                         this does nothing because the given bound is not \
-                         a default. Only `?Sized` is supported",
-                    );
-                }
-            }
-        }
-        _ if kind_id.is_ok() => {
-            return false;
-        }
-        // No lang item for Sized, so we can't add it as a bound.
-        None => {}
-    }
-
-    true
-}
-
 /// Returns the early-bound lifetimes declared in this generics
 /// listing. For anything other than fns/methods, this is just all
 /// the lifetimes that are declared. For fns or methods, we have to
@@ -1984,7 +1934,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                 let opaque_ty = tcx.mk_opaque(def_id, substs);
 
                 // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
-                let bounds = compute_bounds(
+                let bounds = AstConv::compute_bounds(
                     &icx,
                     opaque_ty,
                     bounds,
@@ -2030,7 +1980,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                     let opaque_ty = tcx.mk_opaque(def_id, substs);
 
                     // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
-                    let bounds = compute_bounds(
+                    let bounds = AstConv::compute_bounds(
                         &icx,
                         opaque_ty,
                         bounds,
@@ -2124,7 +2074,7 @@ fn explicit_predicates_of<'a, 'tcx>(
             index += 1;
 
             let sized = SizedByDefault::Yes;
-            let bounds = compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
+            let bounds = AstConv::compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
             predicates.extend(bounds.predicates(tcx, param_ty));
         }
     }
@@ -2159,19 +2109,17 @@ fn explicit_predicates_of<'a, 'tcx>(
                 for bound in bound_pred.bounds.iter() {
                     match bound {
                         &hir::GenericBound::Trait(ref poly_trait_ref, _) => {
-                            let mut projections = Vec::new();
+                            let mut bounds = Bounds::default();
 
                             let (trait_ref, _) = AstConv::instantiate_poly_trait_ref(
                                 &icx,
                                 poly_trait_ref,
                                 ty,
-                                &mut projections,
+                                &mut bounds,
                             );
 
-                            predicates.extend(
-                                iter::once((trait_ref.to_predicate(), poly_trait_ref.span)).chain(
-                                    projections.iter().map(|&(p, span)| (p.to_predicate(), span)
-                            )));
+                            predicates.push((trait_ref.to_predicate(), poly_trait_ref.span));
+                            predicates.extend(bounds.predicates(tcx, ty));
                         }
 
                         &hir::GenericBound::Outlives(ref lifetime) => {
@@ -2210,14 +2158,14 @@ fn explicit_predicates_of<'a, 'tcx>(
             let trait_item = tcx.hir().trait_item(trait_item_ref.id);
             let bounds = match trait_item.node {
                 hir::TraitItemKind::Type(ref bounds, _) => bounds,
-                _ => return vec![].into_iter()
+                _ => return Vec::new().into_iter()
             };
 
             let assoc_ty =
                 tcx.mk_projection(tcx.hir().local_def_id_from_hir_id(trait_item.hir_id),
                     self_trait_ref.substs);
 
-            let bounds = compute_bounds(
+            let bounds = AstConv::compute_bounds(
                 &ItemCtxt::new(tcx, def_id),
                 assoc_ty,
                 bounds,
@@ -2259,68 +2207,6 @@ fn explicit_predicates_of<'a, 'tcx>(
     result
 }
 
-pub enum SizedByDefault {
-    Yes,
-    No,
-}
-
-/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
-/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
-/// built-in trait `Send`.
-pub fn compute_bounds<'gcx: 'tcx, 'tcx>(
-    astconv: &dyn AstConv<'gcx, 'tcx>,
-    param_ty: Ty<'tcx>,
-    ast_bounds: &[hir::GenericBound],
-    sized_by_default: SizedByDefault,
-    span: Span,
-) -> Bounds<'tcx> {
-    let mut region_bounds = Vec::new();
-    let mut trait_bounds = Vec::new();
-
-    for ast_bound in ast_bounds {
-        match *ast_bound {
-            hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => trait_bounds.push(b),
-            hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
-            hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
-        }
-    }
-
-    let mut projection_bounds = Vec::new();
-
-    let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
-        let (poly_trait_ref, _) = astconv.instantiate_poly_trait_ref(
-            bound,
-            param_ty,
-            &mut projection_bounds,
-        );
-        (poly_trait_ref, bound.span)
-    }).collect();
-
-    let region_bounds = region_bounds
-        .into_iter()
-        .map(|r| (astconv.ast_region_to_region(r, None), r.span))
-        .collect();
-
-    trait_bounds.sort_by_key(|(t, _)| t.def_id());
-
-    let implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
-        if !is_unsized(astconv, ast_bounds, span) {
-            Some(span)
-        } else {
-            None
-        }
-    } else {
-        None
-    };
-
-    Bounds {
-        region_bounds,
-        implicitly_sized,
-        trait_bounds,
-        projection_bounds,
-    }
-}
-
 /// Converts a specific `GenericBound` from the AST into a set of
 /// predicates that apply to the self type. A vector is returned
 /// because this can be anywhere from zero predicates (`T: ?Sized` adds no
@@ -2333,13 +2219,11 @@ fn predicates_from_bound<'tcx>(
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     match *bound {
         hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
-            let mut projections = Vec::new();
-            let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections);
-            iter::once((pred.to_predicate(), tr.span)).chain(
-                projections
-                    .into_iter()
-                    .map(|(p, span)| (p.to_predicate(), span))
-            ).collect()
+            let mut bounds = Bounds::default();
+            let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
+            iter::once((pred.to_predicate(), tr.span))
+                .chain(bounds.predicates(astconv.tcx(), param_ty))
+                .collect()
         }
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
@@ -2363,8 +2247,8 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
     };
     let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
 
-    // feature gate SIMD types in FFI, since I (huonw) am not sure the
-    // ABIs are handled at all correctly.
+    // Feature gate SIMD types in FFI, since I am not sure that the
+    // ABIs are handled at all correctly. -huonw
     if abi != abi::Abi::RustIntrinsic
         && abi != abi::Abi::PlatformIntrinsic
         && !tcx.features().simd_ffi
@@ -2439,7 +2323,7 @@ fn from_target_feature(
     };
     let rust_features = tcx.features();
     for item in list {
-        // Only `enable = ...` is accepted in the meta item list
+        // Only `enable = ...` is accepted in the meta-item list.
         if !item.check_name(sym::enable) {
             bad_item(item.span());
             continue;
@@ -2454,9 +2338,9 @@ fn from_target_feature(
             }
         };
 
-        // We allow comma separation to enable multiple features
+        // We allow comma separation to enable multiple features.
         target_features.extend(value.as_str().split(',').filter_map(|feature| {
-            // Only allow whitelisted features per platform
+            // Only allow whitelisted features per platform.
             let feature_gate = match whitelist.get(feature) {
                 Some(g) => g,
                 None => {
@@ -2480,7 +2364,7 @@ fn from_target_feature(
                 }
             };
 
-            // Only allow features whose feature gates have been enabled
+            // Only allow features whose feature gates have been enabled.
             let allowed = match feature_gate.as_ref().map(|s| *s) {
                 Some(sym::arm_target_feature) => rust_features.arm_target_feature,
                 Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 024d73ff65bd2..30993b86a385f 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -114,6 +114,7 @@ use util::common::time;
 
 use std::iter;
 
+use astconv::{AstConv, Bounds};
 pub use collect::checked_type_of;
 
 pub struct TypeAndSubsts<'tcx> {
@@ -390,19 +391,19 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
 }
 
 pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
-        -> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) {
+        -> (ty::PolyTraitRef<'tcx>, Bounds<'tcx>) {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
     let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
     let env_def_id = tcx.hir().local_def_id_from_hir_id(env_hir_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
-    let mut projections = Vec::new();
-    let (principal, _) = astconv::AstConv::instantiate_poly_trait_ref_inner(
-        &item_cx, hir_trait, tcx.types.err, &mut projections, true
+    let mut bounds = Bounds::default();
+    let (principal, _) = AstConv::instantiate_poly_trait_ref_inner(
+        &item_cx, hir_trait, tcx.types.err, &mut bounds, true
     );
 
-    (principal, projections)
+    (principal, bounds)
 }
 
 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f19e5180939ba..161e426604e94 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2445,7 +2445,7 @@ pub struct PolyTrait {
 
 /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
 /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
-/// importantly, it does not preserve mutability or boxes.
+/// importanntly, it does not preserve mutability or boxes.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub enum Type {
     /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
@@ -2939,6 +2939,9 @@ impl Clean<Type> for hir::Ty {
             TyKind::Infer | TyKind::Err => Infer,
             TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
             TyKind::CVarArgs(_) => CVarArgs,
+            TyKind::AssocTyExistential(ref bounds) => {
+                ImplTrait(bounds.into_iter().map(|b| b.clean(cx)).collect())
+            }
         }
     }
 }

From 01f49f0bb2461ebe1987a40c6afea5b1dd30e881 Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Thu, 21 Mar 2019 17:55:09 +0000
Subject: [PATCH 05/24] Use both existential-type desugaring and where-clause
 (predicate) desugaring depending on context.

---
 src/librustc/hir/lowering.rs          | 182 ++++++++++++++++----------
 src/librustc_passes/ast_validation.rs |  46 ++++++-
 src/librustc_typeck/astconv.rs        |  24 ++--
 src/librustc_typeck/collect.rs        |   8 +-
 4 files changed, 173 insertions(+), 87 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 2c2cd6a2f6f53..165723bcfa278 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -106,6 +106,7 @@ pub struct LoweringContext<'a> {
     loop_scopes: Vec<NodeId>,
     is_in_loop_condition: bool,
     is_in_trait_impl: bool,
+    is_in_dyn_type: bool,
 
     /// What to do when we encounter either an "anonymous lifetime
     /// reference". The term "anonymous" is meant to encompass both
@@ -195,12 +196,6 @@ enum ImplTraitContext<'a> {
     /// (e.g., for consts and statics).
     Existential(Option<DefId> /* fn def-ID */),
 
-    /// Treat `impl Trait` as a bound on the associated type applied to the trait.
-    /// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
-    /// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
-    /// { type Bar: Iterator; }`.
-    AssociatedTy,
-
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -208,7 +203,10 @@ enum ImplTraitContext<'a> {
 /// Position in which `impl Trait` is disallowed. Used for error reporting.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum ImplTraitPosition {
+    /// Disallowed in `let` / `const` / `static` bindings.
     Binding,
+
+    /// All other posiitons.
     Other,
 }
 
@@ -223,7 +221,6 @@ impl<'a> ImplTraitContext<'a> {
         match self {
             Universal(params) => Universal(params),
             Existential(fn_def_id) => Existential(*fn_def_id),
-            AssociatedTy => AssociatedTy,
             Disallowed(pos) => Disallowed(*pos),
         }
     }
@@ -256,6 +253,8 @@ pub fn lower_crate(
         catch_scopes: Vec::new(),
         loop_scopes: Vec::new(),
         is_in_loop_condition: false,
+        is_in_trait_impl: false,
+        is_in_dyn_type: false,
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
         type_def_lifetime_params: Default::default(),
         current_module: CRATE_NODE_ID,
@@ -265,7 +264,6 @@ pub fn lower_crate(
         is_generator: false,
         is_async_body: false,
         current_item: None,
-        is_in_trait_impl: false,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
@@ -1230,6 +1228,20 @@ impl<'a> LoweringContext<'a> {
         result
     }
 
+    fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
+    where
+        F: FnOnce(&mut LoweringContext<'_>) -> T,
+    {
+        let was_in_dyn_type = self.is_in_dyn_type;
+        self.is_in_dyn_type = in_scope;
+
+        let result = f(self);
+
+        self.is_in_dyn_type = was_in_dyn_type;
+
+        result
+    }
+
     fn with_new_scopes<T, F>(&mut self, f: F) -> T
     where
         F: FnOnce(&mut LoweringContext<'_>) -> T,
@@ -1353,24 +1365,58 @@ impl<'a> LoweringContext<'a> {
                                  c: &AssocTyConstraint,
                                  itctx: ImplTraitContext<'_>)
                                  -> hir::TypeBinding {
+        debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
+
         let ty = match c.kind {
             AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
             AssocTyConstraintKind::Bound { ref bounds } => {
-                // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
-                let impl_ty_node_id = self.sess.next_node_id();
-                let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
-                self.resolver.definitions().create_def_with_parent(
-                    parent_def_index,
-                    impl_ty_node_id,
-                    DefPathData::Misc,
-                    DefIndexAddressSpace::High,
-                    Mark::root(),
-                    DUMMY_SP);
-                self.lower_ty(&Ty {
-                    id: self.sess.next_node_id(),
-                    node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
-                    span: DUMMY_SP,
-                }, itctx)
+                let (existential_desugaring, itctx) = match itctx {
+                    ImplTraitContext::Existential(_) => (true, itctx),
+                    ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
+                    // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
+                    ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
+                        (true, ImplTraitContext::Existential(None)),
+                    _ => (false, itctx),
+                };
+
+                if existential_desugaring {
+                    // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
+
+                    let impl_ty_node_id = self.sess.next_node_id();
+                    let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+                    self.resolver.definitions().create_def_with_parent(
+                        parent_def_index,
+                        impl_ty_node_id,
+                        DefPathData::Misc,
+                        DefIndexAddressSpace::High,
+                        Mark::root(),
+                        DUMMY_SP
+                    );
+
+                    self.with_dyn_type_scope(false, |this| {
+                        this.lower_ty(
+                            &Ty {
+                                id: this.sess.next_node_id(),
+                                node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
+                                span: DUMMY_SP,
+                            },
+                            itctx,
+                        )
+                    })
+                } else {
+                    // Desugar `AssocTy: Bounds` into `AssocTy = ∃ T (T: Bounds)`, where the
+                    // "false existential" later desugars into a trait predicate.
+
+                    let bounds = self.lower_param_bounds(bounds, itctx);
+
+                    let id = self.sess.next_node_id();
+                    let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
+                    P(hir::Ty {
+                        hir_id,
+                        node: hir::TyKind::AssocTyExistential(bounds),
+                        span: DUMMY_SP,
+                    })
+                }
             }
         };
 
@@ -1477,23 +1523,26 @@ impl<'a> LoweringContext<'a> {
             }
             TyKind::TraitObject(ref bounds, kind) => {
                 let mut lifetime_bound = None;
-                let bounds = bounds
-                    .iter()
-                    .filter_map(|bound| match *bound {
-                        GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
-                            Some(self.lower_poly_trait_ref(ty, itctx.reborrow()))
-                        }
-                        GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
-                        GenericBound::Outlives(ref lifetime) => {
-                            if lifetime_bound.is_none() {
-                                lifetime_bound = Some(self.lower_lifetime(lifetime));
+                let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                    let bounds = bounds
+                        .iter()
+                        .filter_map(|bound| match *bound {
+                            GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
+                                Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
                             }
-                            None
-                        }
-                    })
-                    .collect();
-                let lifetime_bound =
-                    lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
+                            GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+                            GenericBound::Outlives(ref lifetime) => {
+                                if lifetime_bound.is_none() {
+                                    lifetime_bound = Some(this.lower_lifetime(lifetime));
+                                }
+                                None
+                            }
+                        })
+                        .collect();
+                    let lifetime_bound =
+                        lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
+                    (bounds, lifetime_bound)
+                });
                 if kind != TraitObjectSyntax::Dyn {
                     self.maybe_lint_bare_trait(t.span, t.id, false);
                 }
@@ -1544,16 +1593,6 @@ impl<'a> LoweringContext<'a> {
                             }),
                         ))
                     }
-                    ImplTraitContext::AssociatedTy => {
-                        let hir_bounds = self.lower_param_bounds(
-                            bounds,
-                            ImplTraitContext::AssociatedTy,
-                        );
-
-                        hir::TyKind::AssocTyExistential(
-                            hir_bounds,
-                        )
-                    }
                     ImplTraitContext::Disallowed(pos) => {
                         let allowed_in = if self.sess.features_untracked()
                                                 .impl_trait_in_bindings {
@@ -2407,7 +2446,8 @@ impl<'a> LoweringContext<'a> {
                 FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
                     Some((def_id, _)) if impl_trait_return_allow => {
                         hir::Return(self.lower_ty(ty,
-                            ImplTraitContext::Existential(Some(def_id))))
+                            ImplTraitContext::Existential(Some(def_id))
+                        ))
                     }
                     _ => {
                         hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
@@ -2770,7 +2810,7 @@ impl<'a> LoweringContext<'a> {
 
                 let kind = hir::GenericParamKind::Type {
                     default: default.as_ref().map(|x| {
-                        self.lower_ty(x, ImplTraitContext::disallowed())
+                        self.lower_ty(x, ImplTraitContext::Existential(None))
                     }),
                     synthetic: param.attrs.iter()
                                           .filter(|attr| attr.check_name(sym::rustc_synthetic))
@@ -3275,39 +3315,43 @@ impl<'a> LoweringContext<'a> {
             ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
             ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
             ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
-                self.lower_ty(t, ImplTraitContext::AssociatedTy),
-                self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+                self.lower_ty(t, ImplTraitContext::disallowed()),
+                self.lower_generics(generics, ImplTraitContext::disallowed()),
             ),
             ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
                 hir::ExistTy {
-                    generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
-                    bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
+                    generics: self.lower_generics(generics,
+                        ImplTraitContext::Existential(None)),
+                    bounds: self.lower_param_bounds(b,
+                        ImplTraitContext::Existential(None)),
                     impl_trait_fn: None,
                     origin: hir::ExistTyOrigin::ExistentialType,
                 },
             ),
-            ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
-                hir::EnumDef {
-                    variants: enum_definition
-                        .variants
-                        .iter()
-                        .map(|x| self.lower_variant(x))
-                        .collect(),
-                },
-                self.lower_generics(generics, ImplTraitContext::AssociatedTy),
-            ),
+            ItemKind::Enum(ref enum_definition, ref generics) => {
+                hir::ItemKind::Enum(
+                    hir::EnumDef {
+                        variants: enum_definition
+                            .variants
+                            .iter()
+                            .map(|x| self.lower_variant(x))
+                            .collect(),
+                    },
+                    self.lower_generics(generics, ImplTraitContext::disallowed()),
+                )
+            },
             ItemKind::Struct(ref struct_def, ref generics) => {
                 let struct_def = self.lower_variant_data(struct_def);
                 hir::ItemKind::Struct(
                     struct_def,
-                    self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+                    self.lower_generics(generics, ImplTraitContext::disallowed()),
                 )
             }
             ItemKind::Union(ref vdata, ref generics) => {
                 let vdata = self.lower_variant_data(vdata);
                 hir::ItemKind::Union(
                     vdata,
-                    self.lower_generics(generics, ImplTraitContext::AssociatedTy),
+                    self.lower_generics(generics, ImplTraitContext::disallowed()),
                 )
             }
             ItemKind::Impl(
@@ -3675,9 +3719,9 @@ impl<'a> LoweringContext<'a> {
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
             }
             TraitItemKind::Type(ref bounds, ref default) => {
-                let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
+                let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
                 let node = hir::TraitItemKind::Type(
-                    self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
+                    self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
                     default
                         .as_ref()
                         .map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 2d602a7f1b468..532cec2af159e 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -63,6 +63,10 @@ struct AstValidator<'a> {
     /// or `Foo::Bar<impl Trait>`
     is_impl_trait_banned: bool,
 
+    /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
+    /// certain positions.
+    is_assoc_ty_bound_banned: bool,
+
     /// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
     /// until PRs #57730 and #57981 landed: it would jump directly to
     /// walk_ty rather than visit_ty (or skip recurring entirely for
@@ -87,6 +91,12 @@ impl<'a> AstValidator<'a> {
         self.is_impl_trait_banned = old;
     }
 
+    fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
+        f(self);
+        self.is_assoc_ty_bound_banned = old;
+    }
+
     fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
         f(self);
@@ -94,12 +104,21 @@ impl<'a> AstValidator<'a> {
     }
 
     fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
-        if let AssocTyConstraintKind::Equality { ref ty } = constraint.kind {
-            // rust-lang/rust#57979: bug in old `visit_generic_args` called
-            // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
-            // if it happened to occur at `ty`.
-            if let TyKind::ImplTrait(..) = ty.node {
-                self.warning_period_57979_didnt_record_next_impl_trait = true;
+        match constraint.kind {
+            AssocTyConstraintKind::Equality { ref ty } => {
+                // rust-lang/rust#57979: bug in old `visit_generic_args` called
+                // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
+                // if it happened to occur at `ty`.
+                if let TyKind::ImplTrait(..) = ty.node {
+                    self.warning_period_57979_didnt_record_next_impl_trait = true;
+                }
+            }
+            AssocTyConstraintKind::Bound { .. } => {
+                if self.is_assoc_ty_bound_banned {
+                    self.err_handler().span_err(constraint.span,
+                        "associated type bounds are not allowed within structs, enums, or unions"
+                    );
+                }
             }
         }
         self.visit_assoc_ty_constraint(constraint);
@@ -726,7 +745,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
                 // are allowed to contain nested `impl Trait`.
                 self.with_impl_trait(None, |this| {
-                    walk_list!(this, visit_assoc_ty_constraint_from_generic_args, &data.constraints);
+                    walk_list!(this, visit_assoc_ty_constraint_from_generic_args,
+                        &data.constraints);
                 });
             }
             GenericArgs::Parenthesized(ref data) => {
@@ -819,6 +839,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_poly_trait_ref(self, t, m);
     }
 
+    fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident,
+                          _: &'a Generics, _: NodeId, _: Span) {
+        self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
+    }
+
+    fn visit_enum_def(&mut self, enum_definition: &'a EnumDef,
+                      generics: &'a Generics, item_id: NodeId, _: Span) {
+        self.with_banned_assoc_ty_bound(
+            |this| visit::walk_enum_def(this, enum_definition, generics, item_id))
+    }
+
     fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
         // when a new macro kind is added but the author forgets to set it up for expansion
         // because that's the only part that won't cause a compiler error
@@ -842,6 +873,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
         has_global_allocator: false,
         outer_impl_trait: None,
         is_impl_trait_banned: false,
+        is_assoc_ty_bound_banned: false,
         warning_period_57979_didnt_record_next_impl_trait: false,
         warning_period_57979_impl_trait_in_proj: false,
     };
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6123ee2af6e88..5ddb2c974ac02 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -930,13 +930,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             .into_iter()
             .map(|r| (self.ast_region_to_region(r, None), r.span))
         );
-
-        bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
     }
 
-    /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
-    /// or a region) to ty's notion of ty param bounds, which can either be user-defined traits or the
-    /// built-in trait `Send`.
+    /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped
+    /// `Ty` or a region) to ty's notion of ty param bounds, which can either be user-defined traits
+    /// or the built-in trait `Send`.
     pub fn compute_bounds(&self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound],
@@ -944,7 +942,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         span: Span,
     ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
+
         self.add_bounds(param_ty, ast_bounds, &mut bounds);
+        bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
+
         bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
             if !self.is_unsized(ast_bounds, span) {
                 Some(span)
@@ -954,6 +955,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         } else {
             None
         };
+
         bounds
     }
 
@@ -993,7 +995,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
             //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
             if let ConvertedBindingKind::Equality(ty) = binding.kind {
-                let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
+                let late_bound_in_trait_ref =
+                    tcx.collect_constrained_late_bound_regions(&trait_ref);
                 let late_bound_in_ty =
                     tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
                 debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
@@ -1074,8 +1077,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 }), binding.span));
             }
             ConvertedBindingKind::Constraint(ref ast_bounds) => {
+                // Calling `skip_binder` is okay, because the predicates are re-bound later by
+                // `instantiate_poly_trait_ref`.
+                let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
                 self.add_bounds(
-                    trait_ref.self_ty(),
+                    param_ty,
                     ast_bounds,
                     bounds,
                 );
@@ -2050,6 +2056,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
         };
 
+        debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
+
         self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
         result_ty
     }
@@ -2135,7 +2143,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 }
             }
         });
-        debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
+        debug!("impl_trait_ty_to_ty: substs={:?}", substs);
 
         let ty = tcx.mk_opaque(def_id, substs);
         debug!("impl_trait_ty_to_ty: {}", ty);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 92d0e37cb9bbd..90ab596363bff 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -703,7 +703,8 @@ fn super_predicates_of<'a, 'tcx>(
 
     // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
     let self_param_ty = tcx.mk_self_type();
-    let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
+    let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No,
+        item.span);
 
     let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
@@ -1988,15 +1989,16 @@ fn explicit_predicates_of<'a, 'tcx>(
                         tcx.def_span(def_id),
                     );
 
+                    let bounds_predicates = bounds.predicates(tcx, opaque_ty);
                     if impl_trait_fn.is_some() {
                         // opaque types
                         return tcx.arena.alloc(ty::GenericPredicates {
                             parent: None,
-                            predicates: bounds.predicates(tcx, opaque_ty),
+                            predicates: bounds_predicates,
                         });
                     } else {
                         // named existential types
-                        predicates.extend(bounds.predicates(tcx, opaque_ty));
+                        predicates.extend(bounds_predicates);
                         generics
                     }
                 }

From cad1b1847eb6c2b720858f26af16d38d658fbc1a Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Thu, 21 Mar 2019 18:40:00 +0000
Subject: [PATCH 06/24] Added feature gate.

---
 src/librustc/hir/lowering.rs  |  2 +-
 src/libsyntax/feature_gate.rs | 42 +++++++++++++++++++++++++----------
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 165723bcfa278..eab01c0bf9924 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -200,7 +200,7 @@ enum ImplTraitContext<'a> {
     Disallowed(ImplTraitPosition),
 }
 
-/// Position in which `impl Trait` is disallowed. Used for error reporting.
+/// Position in which `impl Trait` is disallowed.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum ImplTraitPosition {
     /// Disallowed in `let` / `const` / `static` bindings.
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b2646efe3e464..4a95b6f69a161 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -15,7 +15,10 @@
 use AttributeType::*;
 use AttributeGate::*;
 
-use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
+use crate::ast::{
+    self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
+    PatKind, RangeEnd,
+};
 use crate::attr;
 use crate::early_buffered_lints::BufferedEarlyLintId;
 use crate::source_map::Spanned;
@@ -554,6 +557,9 @@ declare_features! (
     // Allows using C-variadics.
     (active, c_variadic, "1.34.0", Some(44930), None),
 
+    // Allows the user of associated type bounds.
+    (active, associated_type_bounds, "1.34.0", Some(52662), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -1917,7 +1923,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             self.builtin_attributes.get(&ident.name).map(|a| *a)
         });
 
-        // check for gated attributes
+        // Check for gated attributes.
         self.context.check_attribute(attr, attr_info, false);
 
         if attr.check_name(sym::doc) {
@@ -2115,7 +2121,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
             if let ast::TyKind::Never = output_ty.node {
-                // Do nothing
+                // Do nothing.
             } else {
                 self.visit_ty(output_ty)
             }
@@ -2171,7 +2177,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_expr(self, e);
+        visit::walk_expr(self, e)
     }
 
     fn visit_arm(&mut self, arm: &'a ast::Arm) {
@@ -2220,15 +2226,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
         }
 
-        visit::walk_fn(self, fn_kind, fn_decl, span);
+        visit::walk_fn(self, fn_kind, fn_decl, span)
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        if let GenericParamKind::Const { .. } = param.kind {
-            gate_feature_post!(&self, const_generics, param.ident.span,
-                "const generics are unstable");
+        match param.kind {
+            GenericParamKind::Const { .. } =>
+                gate_feature_post!(&self, const_generics, param.ident.span,
+                    "const generics are unstable"),
+            _ => {}
+        }
+        visit::walk_generic_param(self, param)
+    }
+
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+        match constraint.kind {
+            AssocTyConstraintKind::Bound { .. } =>
+                gate_feature_post!(&self, associated_type_bounds, constraint.span,
+                    "associated type bounds are unstable"),
+            _ => {}
         }
-        visit::walk_generic_param(self, param);
+        visit::walk_assoc_ty_constraint(self, constraint)
     }
 
     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
@@ -2266,7 +2284,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_trait_item(self, ti);
+        visit::walk_trait_item(self, ti)
     }
 
     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
@@ -2298,7 +2316,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii);
+        visit::walk_impl_item(self, ii)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
@@ -2306,7 +2324,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             gate_feature_post!(&self, crate_visibility_modifier, vis.span,
                                "`crate` visibility modifier is experimental");
         }
-        visit::walk_vis(self, vis);
+        visit::walk_vis(self, vis)
     }
 }
 

From 4310ba2c985c161260bbdfef5d92ceea552e9055 Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Sat, 16 Mar 2019 00:03:51 +0000
Subject: [PATCH 07/24] Added test suite.

---
 src/test/run-pass/issues/issue-25700-2.rs     |   2 +-
 .../auxiliary/fn-aux.rs                       | 177 +++++
 .../auxiliary/fn-dyn-aux.rs                   | 182 +++++
 .../bad-bounds-on-assoc-in-trait.rs           |  60 ++
 .../bad-bounds-on-assoc-in-trait.stderr       |  85 +++
 .../bounds-on-assoc-in-trait.rs               |  51 ++
 .../ui/associated-type-bounds/duplicate.rs    | 161 +++++
 .../associated-type-bounds/duplicate.stderr   | 627 ++++++++++++++++++
 .../dyn-existential-type.rs                   |  67 ++
 .../ui/associated-type-bounds/dyn-lcsit.rs    |  69 ++
 .../dyn-rpit-and-let.rs                       |  73 ++
 .../entails-sized-object-safety.rs            |  26 +
 .../ui/associated-type-bounds/enum-bounds.rs  | 122 ++++
 .../existential-type.rs                       |  67 ++
 src/test/ui/associated-type-bounds/fn-apit.rs |  58 ++
 src/test/ui/associated-type-bounds/fn-aux.rs  |  12 +
 .../ui/associated-type-bounds/fn-dyn-apit.rs  |  60 ++
 .../ui/associated-type-bounds/fn-inline.rs    |  62 ++
 .../ui/associated-type-bounds/fn-where.rs     |  78 +++
 .../ui/associated-type-bounds/fn-wrap-apit.rs |  64 ++
 .../implied-region-constraints.rs             |  47 ++
 .../implied-region-constraints.stderr         |  25 +
 .../ui/associated-type-bounds/inside-adt.rs   |  36 +
 .../associated-type-bounds/inside-adt.stderr  |  79 +++
 src/test/ui/associated-type-bounds/lcsit.rs   |  78 +++
 .../nested-lifetime-bounds.rs                 |  25 +
 .../nested-lifetime-bounds.stderr             |   9 +
 src/test/ui/associated-type-bounds/rpit.rs    |  64 ++
 .../associated-type-bounds/struct-bounds.rs   | 115 ++++
 .../ui/associated-type-bounds/trait-params.rs | 116 ++++
 .../ui/associated-type-bounds/type-alias.rs   |  19 +
 .../associated-type-bounds/type-alias.stderr  |  97 +++
 .../ui/associated-type-bounds/union-bounds.rs | 123 ++++
 .../feature-gate-associated_type_bounds.rs    |  71 ++
 ...feature-gate-associated_type_bounds.stderr | 132 ++++
 src/test/ui/type/type-alias-bounds.stderr     |  10 -
 36 files changed, 3138 insertions(+), 11 deletions(-)
 create mode 100644 src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
 create mode 100644 src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
 create mode 100644 src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
 create mode 100644 src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
 create mode 100644 src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
 create mode 100644 src/test/ui/associated-type-bounds/duplicate.rs
 create mode 100644 src/test/ui/associated-type-bounds/duplicate.stderr
 create mode 100644 src/test/ui/associated-type-bounds/dyn-existential-type.rs
 create mode 100644 src/test/ui/associated-type-bounds/dyn-lcsit.rs
 create mode 100644 src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
 create mode 100644 src/test/ui/associated-type-bounds/entails-sized-object-safety.rs
 create mode 100644 src/test/ui/associated-type-bounds/enum-bounds.rs
 create mode 100644 src/test/ui/associated-type-bounds/existential-type.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-apit.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-aux.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-dyn-apit.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-inline.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-where.rs
 create mode 100644 src/test/ui/associated-type-bounds/fn-wrap-apit.rs
 create mode 100644 src/test/ui/associated-type-bounds/implied-region-constraints.rs
 create mode 100644 src/test/ui/associated-type-bounds/implied-region-constraints.stderr
 create mode 100644 src/test/ui/associated-type-bounds/inside-adt.rs
 create mode 100644 src/test/ui/associated-type-bounds/inside-adt.stderr
 create mode 100644 src/test/ui/associated-type-bounds/lcsit.rs
 create mode 100644 src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
 create mode 100644 src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
 create mode 100644 src/test/ui/associated-type-bounds/rpit.rs
 create mode 100644 src/test/ui/associated-type-bounds/struct-bounds.rs
 create mode 100644 src/test/ui/associated-type-bounds/trait-params.rs
 create mode 100644 src/test/ui/associated-type-bounds/type-alias.rs
 create mode 100644 src/test/ui/associated-type-bounds/type-alias.stderr
 create mode 100644 src/test/ui/associated-type-bounds/union-bounds.rs
 create mode 100644 src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
 create mode 100644 src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr

diff --git a/src/test/run-pass/issues/issue-25700-2.rs b/src/test/run-pass/issues/issue-25700-2.rs
index 65de5edce48dd..b161e68abafd0 100644
--- a/src/test/run-pass/issues/issue-25700-2.rs
+++ b/src/test/run-pass/issues/issue-25700-2.rs
@@ -18,5 +18,5 @@ fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
 }
 
 pub fn main() {
-   assert_eq!(record_type::<u32>(3), 42);
+    assert_eq!(record_type::<u32>(3), 42);
 }
diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
new file mode 100644
index 0000000000000..0ea23ad1dbffa
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
@@ -0,0 +1,177 @@
+// Traits:
+
+pub trait Alpha {
+    fn alpha(self) -> usize;
+}
+
+pub trait Beta {
+    type Gamma;
+    fn gamma(self) -> Self::Gamma;
+}
+
+pub trait Delta {
+    fn delta(self) -> usize;
+}
+
+pub trait Epsilon<'a> {
+    type Zeta;
+    fn zeta(&'a self) -> Self::Zeta;
+
+    fn epsilon(&'a self) -> usize;
+}
+
+pub trait Eta {
+    fn eta(self) -> usize;
+}
+
+// Assertions:
+
+pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
+pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
+pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
+pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
+pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
+pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
+where
+    T: for<'a> Epsilon<'a>,
+    for<'a> <T as Epsilon<'a>>::Zeta: Eta,
+{
+    x.epsilon() + x.zeta().eta()
+}
+
+// Implementations and types:
+
+#[derive(Copy, Clone)]
+pub struct BetaType;
+
+#[derive(Copy, Clone)]
+pub struct GammaType;
+
+#[derive(Copy, Clone)]
+pub struct ZetaType;
+
+impl Beta for BetaType {
+    type Gamma = GammaType;
+    fn gamma(self) -> Self::Gamma { GammaType }
+}
+
+impl<'a> Beta for &'a BetaType {
+    type Gamma = GammaType;
+    fn gamma(self) -> Self::Gamma { GammaType }
+}
+
+impl Beta for GammaType {
+    type Gamma = Self;
+    fn gamma(self) -> Self::Gamma { self }
+}
+
+impl Alpha for GammaType {
+    fn alpha(self) -> usize { 42 }
+}
+
+impl Delta for GammaType {
+    fn delta(self) -> usize { 1337 }
+}
+
+impl<'a> Epsilon<'a> for GammaType {
+    type Zeta = ZetaType;
+    fn zeta(&'a self) -> Self::Zeta { ZetaType }
+
+    fn epsilon(&'a self) -> usize { 7331 }
+}
+
+impl Eta for ZetaType {
+    fn eta(self) -> usize { 7 }
+}
+
+// Desugared forms to check against:
+
+pub fn desugared_bound<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Alpha
+{
+    let gamma: B::Gamma = beta.gamma();
+    assert_alpha::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: 'static,
+{
+    assert_static::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_multi<B>(beta: B) -> usize
+where
+    B: Copy + Beta,
+    B::Gamma: Alpha + 'static + Delta,
+{
+    assert_alpha::<B::Gamma>(beta.gamma()) +
+    assert_static::<B::Gamma>(beta.gamma()) +
+    assert_delta::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta,
+    B::Gamma: 'a + Epsilon<'a>,
+{
+    assert_epsilon_specific::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region_forall<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+{
+    assert_epsilon_forall::<B::Gamma>();
+    let g1: B::Gamma = beta.gamma();
+    let g2: B::Gamma = g1;
+    assert_epsilon_specific::<B::Gamma>(&g1) +
+    assert_epsilon_specific::<B::Gamma>(&g2)
+}
+
+pub fn desugared_bound_region_forall2<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+    for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
+{
+    let gamma = beta.gamma();
+    assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
+}
+
+pub fn desugared_contraint_region_forall<B>(beta: B) -> usize
+where
+    for<'a> &'a B: Beta,
+    for<'a> <&'a B as Beta>::Gamma: Alpha,
+{
+    let g1 = beta.gamma();
+    let g2 = beta.gamma();
+    assert_alpha(g1) + assert_alpha(g2)
+}
+
+pub fn desugared_bound_nested<B>(beta: B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + Alpha + Beta,
+    <B::Gamma as Beta>::Gamma: Delta,
+{
+    let go = beta.gamma();
+    let gi = go.gamma();
+    go.alpha() + gi.delta()
+}
+
+pub fn desugared() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, desugared_bound(beta));
+    assert_eq!(24, desugared_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
+    assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, desugared_bound_region_forall(beta));
+    assert_eq!(42 + 1337, desugared_bound_nested(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
new file mode 100644
index 0000000000000..85d6c5aaf3c6f
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
@@ -0,0 +1,182 @@
+// Traits:
+
+pub trait Alpha {
+    fn alpha(self) -> usize;
+}
+
+pub trait Beta {
+    type Gamma;
+    fn gamma(&self) -> Self::Gamma;
+}
+
+pub trait Delta {
+    fn delta(self) -> usize;
+}
+
+pub trait Epsilon<'a> {
+    type Zeta;
+    fn zeta(&'a self) -> Self::Zeta;
+
+    fn epsilon(&'a self) -> usize;
+}
+
+pub trait Eta {
+    fn eta(self) -> usize;
+}
+
+// Assertions:
+
+pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
+pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
+pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
+pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
+pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
+pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
+where
+    T: for<'a> Epsilon<'a>,
+    for<'a> <T as Epsilon<'a>>::Zeta: Eta,
+{
+    x.epsilon() + x.zeta().eta()
+}
+
+// Implementations and types:
+
+#[derive(Copy, Clone)]
+pub struct BetaType;
+
+#[derive(Copy, Clone)]
+pub struct GammaType;
+
+#[derive(Copy, Clone)]
+pub struct ZetaType;
+
+impl<T> Beta for &(dyn Beta<Gamma = T> + Send) {
+    type Gamma = T;
+    fn gamma(&self) -> Self::Gamma { (*self).gamma() }
+}
+
+impl Beta for BetaType {
+    type Gamma = GammaType;
+    fn gamma(&self) -> Self::Gamma { GammaType }
+}
+
+impl<'a> Beta for &'a BetaType {
+    type Gamma = GammaType;
+    fn gamma(&self) -> Self::Gamma { GammaType }
+}
+
+impl Beta for GammaType {
+    type Gamma = Self;
+    fn gamma(&self) -> Self::Gamma { Self }
+}
+
+impl Alpha for GammaType {
+    fn alpha(self) -> usize { 42 }
+}
+
+impl Delta for GammaType {
+    fn delta(self) -> usize { 1337 }
+}
+
+impl<'a> Epsilon<'a> for GammaType {
+    type Zeta = ZetaType;
+    fn zeta(&'a self) -> Self::Zeta { ZetaType }
+
+    fn epsilon(&'a self) -> usize { 7331 }
+}
+
+impl Eta for ZetaType {
+    fn eta(self) -> usize { 7 }
+}
+
+// Desugared forms to check against:
+
+pub fn desugared_bound<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Alpha
+{
+    let gamma: B::Gamma = beta.gamma();
+    assert_alpha::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: 'static,
+{
+    assert_static::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_multi<B: ?Sized>(beta: B) -> usize
+where
+    B: Copy + Beta,
+    B::Gamma: Alpha + 'static + Delta,
+{
+    assert_alpha::<B::Gamma>(beta.gamma()) +
+    assert_static::<B::Gamma>(beta.gamma()) +
+    assert_delta::<B::Gamma>(beta.gamma())
+}
+
+pub fn desugared_bound_region_specific<'a, B: ?Sized>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta,
+    B::Gamma: 'a + Epsilon<'a>,
+{
+    assert_epsilon_specific::<B::Gamma>(gamma)
+}
+
+pub fn desugared_bound_region_forall<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+{
+    assert_epsilon_forall::<B::Gamma>();
+    let g1: B::Gamma = beta.gamma();
+    let g2: B::Gamma = g1;
+    assert_epsilon_specific::<B::Gamma>(&g1) +
+    assert_epsilon_specific::<B::Gamma>(&g2)
+}
+
+pub fn desugared_bound_region_forall2<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + for<'a> Epsilon<'a>,
+    for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
+{
+    let gamma = beta.gamma();
+    assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
+}
+
+pub fn desugared_contraint_region_forall<B: ?Sized>(beta: &B) -> usize
+where
+    for<'a> &'a B: Beta,
+    for<'a> <&'a B as Beta>::Gamma: Alpha,
+{
+    let g1 = beta.gamma();
+    let g2 = beta.gamma();
+    assert_alpha(g1) + assert_alpha(g2)
+}
+
+pub fn desugared_bound_nested<B: ?Sized>(beta: &B) -> usize
+where
+    B: Beta,
+    B::Gamma: Copy + Alpha + Beta,
+    <B::Gamma as Beta>::Gamma: Delta,
+{
+    let go = beta.gamma();
+    let gi = go.gamma();
+    go.alpha() + gi.delta()
+}
+
+pub fn desugared() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, desugared_bound(&beta));
+    assert_eq!(24, desugared_bound_region(&beta));
+    assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
+    assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, desugared_bound_region_forall(&beta));
+    assert_eq!(42 + 1337, desugared_bound_nested(&beta));
+}
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
new file mode 100644
index 0000000000000..78704a9b51239
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
@@ -0,0 +1,60 @@
+// compile-fail
+// ignore-tidy-linelength
+
+// NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
+// This should hopefully be fixed with Chalk.
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+use std::iter::Once;
+
+trait Lam<Binder> { type App; }
+
+#[derive(Clone)]
+struct L1;
+impl<'a> Lam<&'a u8> for L1 { type App = u8; }
+
+#[derive(Clone)]
+struct L2;
+impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
+
+trait Case1 {
+    type C: Clone + Iterator<Item:
+        Send + Iterator<Item:
+            for<'a> Lam<&'a u8, App:
+                Debug
+            >
+        > + Sync>;
+}
+
+pub struct S1;
+impl Case1 for S1 {
+//~^ ERROR `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
+    type C = Once<Once<L1>>;
+}
+
+fn assume_case1<T: Case1>() {
+//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277]
+//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277]
+    fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
+    assert_a::<_, T::A>();
+
+    fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
+    assert_b::<_, T::B>();
+
+    fn assert_c<_0, _1, _2, C>()
+    where
+        C: Clone + Iterator<Item = _2>,
+        _2: Send + Iterator<Item = _1>,
+        _1: for<'a> Lam<&'a u8, App = _0>,
+        _0: Debug,
+    {}
+    assert_c::<_, _, _, T::C>();
+}
+
+fn main() {
+    assume_case1(S1);
+}
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
new file mode 100644
index 0000000000000..aebf29cc332ab
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -0,0 +1,85 @@
+error[E0277]: `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:32:6
+   |
+LL | impl Case1 for S1 {
+   |      ^^^^^ `<L1 as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<L1 as Lam<&'a u8>>::App`
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
+   |
+   = help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
+   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
+   |
+LL | / fn assume_case1<T: Case1>() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     assert_c::<_, _, _, T::C>();
+LL | | }
+   | |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+   |
+   = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App`
+note: required by `Case1`
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
+   |
+LL | trait Case1 {
+   | ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
new file mode 100644
index 0000000000000..8c9110d03ec16
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
@@ -0,0 +1,51 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+use std::iter::Empty;
+use std::ops::Range;
+
+trait Lam<Binder> { type App; }
+
+#[derive(Clone)]
+struct L1;
+impl<'a> Lam<&'a u8> for L1 { type App = u8; }
+
+#[derive(Clone)]
+struct L2;
+impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
+
+trait Case1 {
+    type A: Iterator<Item: Debug>;
+
+    type B: Iterator<Item: 'static>;
+}
+
+pub struct S1;
+impl Case1 for S1 {
+    type A = Empty<String>;
+    type B = Range<u16>;
+}
+
+// Ensure we don't have existential desugaring:
+
+pub trait Foo { type Out: Baz<Assoc: Default>; }
+pub trait Baz { type Assoc; }
+
+#[derive(Default)]
+struct S2;
+#[derive(Default)]
+struct S3;
+struct S4;
+struct S5;
+struct S6;
+struct S7;
+
+impl Foo for S6 { type Out = S4; }
+impl Foo for S7 { type Out = S5; }
+
+impl Baz for S4 { type Assoc = S2; }
+impl Baz for S5 { type Assoc = S3; }
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
new file mode 100644
index 0000000000000..bee56d6f68990
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -0,0 +1,161 @@
+// compile-fail
+// ignore-tidy-linelength
+// error-pattern:could not find defining uses
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+#![feature(impl_trait_in_bindings)]
+#![feature(untagged_unions)]
+
+use std::iter;
+
+struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS1: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS2: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRS3: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
+//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
new file mode 100644
index 0000000000000..fbf02ddc7032f
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -0,0 +1,627 @@
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:12:36
+   |
+LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:14:36
+   |
+LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:16:39
+   |
+LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+   |                        -------------  ^^^^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:18:45
+   |
+LL | struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:20:45
+   |
+LL | struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:22:48
+   |
+LL | struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+   |                                 -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:25:34
+   |
+LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:27:34
+   |
+LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:29:37
+   |
+LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
+   |                      -------------  ^^^^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:31:43
+   |
+LL | enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:33:43
+   |
+LL | enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:35:46
+   |
+LL | enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:38:35
+   |
+LL | union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:40:35
+   |
+LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:42:38
+   |
+LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
+   |                       -------------  ^^^^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:44:44
+   |
+LL | union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:46:44
+   |
+LL | union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:48:47
+   |
+LL | union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
+   |                                -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:51:32
+   |
+LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
+   |                    ----------  ^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:53:32
+   |
+LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
+   |                    ----------  ^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:55:35
+   |
+LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
+   |                    -------------  ^^^^^^^^^^^^^ re-bound here
+   |                    |
+   |                    `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:57:43
+   |
+LL | fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:59:43
+   |
+LL | fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:61:46
+   |
+LL | fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:70:40
+   |
+LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:72:40
+   |
+LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:74:43
+   |
+LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:64:42
+   |
+LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:66:42
+   |
+LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:68:45
+   |
+LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
+   |                              -------------  ^^^^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:77:39
+   |
+LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+   |                           ----------  ^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:79:39
+   |
+LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+   |                           ----------  ^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:81:42
+   |
+LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+   |                           -------------  ^^^^^^^^^^^^^ re-bound here
+   |                           |
+   |                           `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:83:40
+   |
+LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:85:40
+   |
+LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:87:43
+   |
+LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:90:46
+   |
+LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:92:46
+   |
+LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:94:49
+   |
+LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:97:35
+   |
+LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:99:35
+   |
+LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
+   |                       ----------  ^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:101:38
+   |
+LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
+   |                       -------------  ^^^^^^^^^^^^^ re-bound here
+   |                       |
+   |                       `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:103:44
+   |
+LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:105:44
+   |
+LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:107:47
+   |
+LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
+   |                                -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:110:1
+   |
+LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:110:48
+   |
+LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
+   |                                    ----------  ^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:112:1
+   |
+LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:112:48
+   |
+LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
+   |                                    ----------  ^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:114:1
+   |
+LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:114:51
+   |
+LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
+   |                                    -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                    |
+   |                                    `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:116:1
+   |
+LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:116:46
+   |
+LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:118:1
+   |
+LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:118:46
+   |
+LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error: could not find defining uses
+  --> $DIR/duplicate.rs:120:1
+   |
+LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:120:49
+   |
+LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:123:36
+   |
+LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:125:36
+   |
+LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
+   |                        ----------  ^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:127:39
+   |
+LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
+   |                        -------------  ^^^^^^^^^^^^^ re-bound here
+   |                        |
+   |                        `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:129:34
+   |
+LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:131:34
+   |
+LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:133:37
+   |
+LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
+   |                      -------------  ^^^^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:135:45
+   |
+LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:137:45
+   |
+LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
+   |                                 ----------  ^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:139:48
+   |
+LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
+   |                                 -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                 |
+   |                                 `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:141:46
+   |
+LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:143:46
+   |
+LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:145:49
+   |
+LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:147:43
+   |
+LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:149:43
+   |
+LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:151:46
+   |
+LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:154:40
+   |
+LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:156:44
+   |
+LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
+   |                                ----------  ^^^^^^^^^^ re-bound here
+   |                                |
+   |                                `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:158:43
+   |
+LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: aborting due to 93 previous errors
+
+For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/associated-type-bounds/dyn-existential-type.rs b/src/test/ui/associated-type-bounds/dyn-existential-type.rs
new file mode 100644
index 0000000000000..dc0afaa934a9e
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-existential-type.rs
@@ -0,0 +1,67 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+type Et1 = Box<dyn Tr1<As1: Copy>>;
+fn def_et1() -> Et1 { Box::new(S1) }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+type Et2 = Box<dyn Tr1<As1: 'static>>;
+fn def_et2() -> Et2 { Box::new(S1) }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+type Et3 = Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>>;
+fn def_et3() -> Et3 {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    Box::new(A)
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+type Et4 = Box<dyn Tr1<As1: for<'a> Tr2<'a>>>;
+fn def_et4() -> Et4 {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    Box::new(A)
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.rs b/src/test/ui/associated-type-bounds/dyn-lcsit.rs
new file mode 100644
index 0000000000000..439304fd309c8
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-lcsit.rs
@@ -0,0 +1,69 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(impl_trait_in_bindings)]
+
+#![allow(non_upper_case_globals)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+#[derive(Copy, Clone)]
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+const cdef_et1: &dyn Tr1<As1: Copy> = &S1;
+const sdef_et1: &dyn Tr1<As1: Copy> = &S1;
+pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
+
+const cdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
+static sdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
+pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
+
+const cdef_et3: &dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    &A
+};
+pub fn use_et3() {
+    let _0 = cdef_et3.mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+const cdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    &A
+};
+static sdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = cdef_et4;
+pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
new file mode 100644
index 0000000000000..f22a6c44cb84d
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
@@ -0,0 +1,73 @@
+// run-pass
+
+// FIXME: uncomment let binding types below when `impl_trait_in_bindings` feature is fixed.
+
+#![feature(associated_type_bounds)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+fn def_et1() -> Box<dyn Tr1<As1: Copy>> {
+    let x /* : Box<dyn Tr1<As1: Copy>> */ = Box::new(S1);
+    x
+}
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+fn def_et2() -> Box<dyn Tr1<As1: Send + 'static>> {
+    let x /* : Box<dyn Tr1<As1: Send + 'static>> */ = Box::new(S1);
+    x
+}
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+fn def_et3() -> Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    let x /* : Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> */
+        = Box::new(A);
+    x
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+fn def_et4() -> Box<dyn Tr1<As1: for<'a> Tr2<'a>>> {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    let x /* : Box<dyn Tr1<As1: for<'a> Tr2<'a>>> */ = Box::new(A);
+    x
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs
new file mode 100644
index 0000000000000..1b3e978594d69
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/entails-sized-object-safety.rs
@@ -0,0 +1,26 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1: Sized { type As1; }
+trait Tr2<'a>: Sized { type As2; }
+
+trait ObjTr1 { fn foo() -> Self where Self: Tr1<As1: Copy>; }
+fn _assert_obj_safe_1(_: Box<dyn ObjTr1>) {}
+
+trait ObjTr2 { fn foo() -> Self where Self: Tr1<As1: 'static>; }
+fn _assert_obj_safe_2(_: Box<dyn ObjTr2>) {}
+
+trait ObjTr3 { fn foo() -> Self where Self: Tr1<As1: Into<u8> + 'static + Copy>; }
+fn _assert_obj_safe_3(_: Box<dyn ObjTr3>) {}
+
+trait ObjTr4 { fn foo() -> Self where Self: Tr1<As1: for<'a> Tr2<'a>>; }
+fn _assert_obj_safe_4(_: Box<dyn ObjTr4>) {}
+
+trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1<As1: Tr2<'a>>; }
+fn _assert_obj_safe_5(_: Box<dyn ObjTr5>) {}
+
+trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1<As1: Tr2<'a, As2: for<'b> Tr2<'b>>>; }
+fn _assert_obj_safe_6(_: Box<dyn ObjTr6>) {}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/enum-bounds.rs b/src/test/ui/associated-type-bounds/enum-bounds.rs
new file mode 100644
index 0000000000000..a6b0bb7070b7a
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/enum-bounds.rs
@@ -0,0 +1,122 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 { type As3; }
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 { type As3 = fn() -> u8; }
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+enum En1<T: Tr1<As1: Tr2>> {
+    Outest(T),
+    Outer(T::As1),
+    Inner(<T::As1 as Tr2>::As2),
+}
+
+fn wrap_en1_1<T>(x: T) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Outest(x)
+}
+
+fn wrap_en1_2<T>(x: T::As1) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Outer(x)
+}
+
+fn wrap_en1_3<T>(x: <T::As1 as Tr2>::As2) -> En1<T> where T: Tr1, T::As1: Tr2 {
+    En1::Inner(x)
+}
+
+enum En2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    V0(T),
+    V1(T::As1),
+    V2(<T::As1 as Tr2>::As2),
+    V3(<<T::As1 as Tr2>::As2 as Tr3>::As3),
+}
+
+enum En3<T: Tr1<As1: 'static>> {
+    V0(T),
+    V1(&'static T::As1),
+}
+
+enum En4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
+    V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
+}
+
+enum _En5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    _V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
+    _V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
+}
+
+enum En6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    V0(T),
+    V1(<T::As1 as Tr2>::As2),
+    V2(&'static T::As1),
+    V3(<T::As1 as Tr5>::As5),
+}
+
+enum _En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    V0(&'a T),
+    V1(&'b <T::As1 as Tr2>::As2),
+}
+
+fn _make_en7<'a, 'b, T>(x: _En7<'a, 'b, T>)
+where
+    T: Tr1<As1: Tr2>,
+{
+    match x {
+        _En7::V0(x) => {
+            let _: &'a T = &x;
+        },
+        _En7::V1(_) => {},
+    }
+}
+
+enum EnSelf<T> where Self: Tr1<As1: Tr2> {
+    V0(T),
+    V1(<Self as Tr1>::As1),
+    V2(<<Self as Tr1>::As1 as Tr2>::As2),
+}
+
+impl Tr1 for EnSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    if let En1::Outest("foo") = wrap_en1_1::<_>("foo") {} else { panic!() };
+    if let En1::Outer(true) = wrap_en1_2::<&str>(true) {} else { panic!() };
+    if let En1::Inner(24u8) = wrap_en1_3::<&str>(24u8) {} else { panic!() };
+
+    let _ = En2::<_>::V0("151571");
+    let _ = En2::<&str>::V1(false);
+    let _ = En2::<&str>::V2(42u8);
+    let _ = En2::<&str>::V3(|| 12u8);
+
+    let _ = En3::<_>::V0("deadbeef");
+    let _ = En3::<&str>::V1(&true);
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let _ = En4::<()>::V0(&f1.0);
+    let _ = En4::<()>::V1(&f2.0);
+
+    let _ = En6::<_>::V0("bar");
+    let _ = En6::<&str>::V1(24u8);
+    let _ = En6::<&str>::V2(&false);
+    let _ = En6::<&str>::V3(12u16);
+
+    let _ = EnSelf::<_>::V0("foo");
+    let _ = EnSelf::<&'static str>::V1(true);
+    let _ = EnSelf::<&'static str>::V2(24u8);
+}
diff --git a/src/test/ui/associated-type-bounds/existential-type.rs b/src/test/ui/associated-type-bounds/existential-type.rs
new file mode 100644
index 0000000000000..87046aec5c4ab
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/existential-type.rs
@@ -0,0 +1,67 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(existential_type)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
+
+existential type Et1: Tr1<As1: Copy>;
+fn def_et1() -> Et1 { S1 }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+existential type Et2: Tr1<As1: 'static>;
+fn def_et2() -> Et2 { S1 }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+existential type Et3: Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>;
+fn def_et3() -> Et3 {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(self) -> Self::As1 { 0..10 }
+    };
+    A
+}
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+existential type Et4: Tr1<As1: for<'a> Tr2<'a>>;
+fn def_et4() -> Et4 {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    A
+}
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/fn-apit.rs b/src/test/ui/associated-type-bounds/fn-apit.rs
new file mode 100644
index 0000000000000..7e208b4e70d81
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-apit.rs
@@ -0,0 +1,58 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+fn apit_bound(beta: impl Beta<Gamma: Alpha>) -> usize {
+    desugared_bound(beta)
+}
+
+fn apit_bound_region(beta: impl Beta<Gamma: 'static>) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn apit_bound_multi(
+    beta: impl Copy + Beta<Gamma: Alpha + 'static + Delta>
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn apit_bound_region_forall(
+    beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn apit_bound_region_forall2(
+    beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn apit_bound_nested(
+    beta: impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn apit_bound_nested2(
+    beta: impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, apit_bound(beta));
+    assert_eq!(24, apit_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, apit_bound_multi(beta));
+    assert_eq!(7331 * 2, apit_bound_region_forall(beta));
+    assert_eq!(42 + 1337, apit_bound_nested(beta));
+    assert_eq!(42 + 1337, apit_bound_nested2(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-aux.rs b/src/test/ui/associated-type-bounds/fn-aux.rs
new file mode 100644
index 0000000000000..434bdbe996c63
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-aux.rs
@@ -0,0 +1,12 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+fn main() {
+    desugared();
+}
diff --git a/src/test/ui/associated-type-bounds/fn-dyn-apit.rs b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
new file mode 100644
index 0000000000000..9ff4a50e1e6e4
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-dyn-apit.rs
@@ -0,0 +1,60 @@
+// run-pass
+// aux-build:fn-dyn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_dyn_aux;
+
+use fn_dyn_aux::*;
+
+// ATB, APIT (dyn trait):
+
+fn dyn_apit_bound(beta: &dyn Beta<Gamma: Alpha>) -> usize {
+    desugared_bound(beta)
+}
+
+fn dyn_apit_bound_region(beta: &dyn Beta<Gamma: 'static>) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn dyn_apit_bound_multi(
+    beta: &(dyn Beta<Gamma: Alpha + 'static + Delta> + Send)
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn dyn_apit_bound_region_forall(
+    beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a>>
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn dyn_apit_bound_region_forall2(
+    beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn dyn_apit_bound_nested(
+    beta: &dyn Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn dyn_apit_bound_nested2(
+    beta: &dyn Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, dyn_apit_bound(&beta));
+    assert_eq!(24, dyn_apit_bound_region(&beta));
+    assert_eq!(42 + 24 + 1337, dyn_apit_bound_multi(&beta));
+    assert_eq!(7331 * 2, dyn_apit_bound_region_forall(&beta));
+    assert_eq!(42 + 1337, dyn_apit_bound_nested(&beta));
+    assert_eq!(42 + 1337, dyn_apit_bound_nested2(&beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-inline.rs b/src/test/ui/associated-type-bounds/fn-inline.rs
new file mode 100644
index 0000000000000..7b188763b7a5e
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-inline.rs
@@ -0,0 +1,62 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, Type parameters, Inline bounds:
+
+fn inline_bound<B: Beta<Gamma: Alpha>>(beta: B) -> usize {
+    desugared_bound(beta)
+}
+
+fn inline_bound_region<B: Beta<Gamma: 'static>>(beta: B) -> usize {
+    desugared_bound_region(beta)
+}
+
+fn inline_bound_multi<B: Copy + Beta<Gamma: Alpha + 'static + Delta>>(
+    beta: B
+) -> usize {
+    desugared_bound_multi(beta)
+}
+
+fn inline_bound_region_specific<'a, B: Beta<Gamma: 'a + Epsilon<'a>>>(
+    gamma: &'a B::Gamma
+) -> usize {
+    desugared_bound_region_specific::<B>(gamma)
+}
+
+fn inline_bound_region_forall<B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>>(
+    beta: B
+) -> usize {
+    desugared_bound_region_forall(beta)
+}
+
+fn inline_bound_region_forall2<B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>(
+    beta: B
+) -> usize {
+    desugared_bound_region_forall2(beta)
+}
+
+fn inline_bound_nested<B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>(
+    beta: B
+) -> usize {
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, inline_bound(beta));
+    assert_eq!(24, inline_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, inline_bound_multi(beta));
+    assert_eq!(7331, inline_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, inline_bound_region_forall(beta));
+    // FIXME: requires lazy normalization.
+    // assert_eq!(7331 * 2, inline_bound_region_forall2(beta));
+    assert_eq!(42 + 1337, inline_bound_nested(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-where.rs b/src/test/ui/associated-type-bounds/fn-where.rs
new file mode 100644
index 0000000000000..60d7149a56f25
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-where.rs
@@ -0,0 +1,78 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, Type parameters, Where-clauses:
+
+fn where_bound<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Alpha>
+{
+    desugared_bound(beta)
+}
+
+fn where_bound_region<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: 'static>
+{
+    desugared_bound_region(beta)
+}
+
+fn where_bound_multi<B>(beta: B) -> usize
+where
+    B: Copy + Beta<Gamma: Alpha + 'static + Delta>,
+{
+    desugared_bound_multi(beta)
+}
+
+fn where_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
+where
+    B: Beta<Gamma: 'a + Epsilon<'a>>,
+{
+    desugared_bound_region_specific::<B>(gamma)
+}
+
+fn where_bound_region_forall<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>,
+{
+    desugared_bound_region_forall(beta)
+}
+
+fn where_bound_region_forall2<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>,
+{
+    desugared_bound_region_forall2(beta)
+}
+
+fn where_contraint_region_forall<B>(beta: B) -> usize
+where
+    for<'a> &'a B: Beta<Gamma: Alpha>,
+{
+    desugared_contraint_region_forall(beta)
+}
+
+fn where_bound_nested<B>(beta: B) -> usize
+where
+    B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>,
+{
+    desugared_bound_nested(beta)
+}
+
+fn main() {
+    let beta = BetaType;
+    let gamma = beta.gamma();
+
+    assert_eq!(42, where_bound(beta));
+    assert_eq!(24, where_bound_region(beta));
+    assert_eq!(42 + 24 + 1337, where_bound_multi(beta));
+    assert_eq!(7331, where_bound_region_specific::<BetaType>(&gamma));
+    assert_eq!(7331 * 2, where_bound_region_forall::<BetaType>(beta));
+    assert_eq!(42 + 1337, where_bound_nested::<BetaType>(beta));
+}
diff --git a/src/test/ui/associated-type-bounds/fn-wrap-apit.rs b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
new file mode 100644
index 0000000000000..23790d416e1f7
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/fn-wrap-apit.rs
@@ -0,0 +1,64 @@
+// run-pass
+// aux-build:fn-aux.rs
+
+#![feature(associated_type_bounds)]
+
+extern crate fn_aux;
+
+use fn_aux::*;
+
+// ATB, APIT + Wrap:
+
+struct Wrap<T>(T);
+
+fn wrap_apit_bound(beta: Wrap<impl Beta<Gamma: Alpha>>) -> usize {
+    desugared_bound(beta.0)
+}
+
+fn wrap_apit_bound_region(beta: Wrap<impl Beta<Gamma: 'static>>) -> usize {
+    desugared_bound_region(beta.0)
+}
+
+fn wrap_apit_bound_multi(
+    beta: Wrap<impl Copy + Beta<Gamma: Alpha + 'static + Delta>>
+) -> usize {
+    desugared_bound_multi(beta.0)
+}
+
+fn wrap_apit_bound_region_forall(
+    beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>>
+) -> usize {
+    desugared_bound_region_forall(beta.0)
+}
+
+fn wrap_apit_bound_region_forall2(
+    beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>
+) -> usize {
+    desugared_bound_region_forall2(beta.0)
+}
+
+fn wrap_apit_bound_nested(
+    beta: Wrap<impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>
+) -> usize {
+    desugared_bound_nested(beta.0)
+}
+
+fn wrap_apit_bound_nested2(
+    beta: Wrap<impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>>
+) -> usize {
+    desugared_bound_nested(beta.0)
+}
+
+fn main() {
+    let beta = BetaType;
+    let _gamma = beta.gamma();
+
+    assert_eq!(42, wrap_apit_bound(Wrap(beta)));
+    assert_eq!(24, wrap_apit_bound_region(Wrap(beta)));
+    assert_eq!(42 + 24 + 1337, wrap_apit_bound_multi(Wrap(beta)));
+    assert_eq!(7331 * 2, wrap_apit_bound_region_forall(Wrap(beta)));
+    // FIXME: requires lazy normalization.
+    // assert_eq!(7331 * 2, wrap_apit_bound_region_forall2(Wrap(beta)));
+    assert_eq!(42 + 1337, wrap_apit_bound_nested(Wrap(beta)));
+    assert_eq!(42 + 1337, wrap_apit_bound_nested2(Wrap(beta)));
+}
diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.rs b/src/test/ui/associated-type-bounds/implied-region-constraints.rs
new file mode 100644
index 0000000000000..4dbaab50a61db
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.rs
@@ -0,0 +1,47 @@
+// compile-fail
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+
+struct St<'a, 'b, T: Tr1<As1: Tr2>> { // `T: 'b` is *not* implied!
+    f0: &'a T, // `T: 'a` is implied.
+    f1: &'b <T::As1 as Tr2>::As2, // `<T::As1 as Tr2>::As2: 'a` is implied.
+}
+
+fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    // This should fail because `T: 'b` is not implied from `WF(St<'a, 'b, T>)`.
+    let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
+    //~^ ERROR lifetime mismatch [E0623]
+}
+
+enum En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    V0(&'a T),
+    V1(&'b <T::As1 as Tr2>::As2),
+}
+
+fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    match x {
+        En7::V0(x) => {
+            // Also fails for the same reason as above:
+            let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
+            //~^ ERROR lifetime mismatch [E0623]
+        },
+        En7::V1(_) => {},
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
new file mode 100644
index 0000000000000..b07b20272a8c0
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
@@ -0,0 +1,25 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/implied-region-constraints.rs:19:64
+   |
+LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
+   |                          -------------
+   |                          |
+   |                          this type is declared with multiple lifetimes...
+...
+LL |     let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
+   |                                                                ^^^^^ ...but data with one lifetime flows into the other here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/implied-region-constraints.rs:40:72
+   |
+LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
+   |                           --------------
+   |                           |
+   |                           this type is declared with multiple lifetimes...
+...
+LL |             let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
+   |                                                                        ^^ ...but data with one lifetime flows into the other here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
new file mode 100644
index 0000000000000..1257dc6e94b39
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -0,0 +1,36 @@
+// compile-fail
+// ignore-tidy-linelength
+// error-pattern:could not find defining uses
+
+#![feature(associated_type_bounds)]
+#![feature(untagged_unions)]
+
+struct S1 { f: dyn Iterator<Item: Copy> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+struct S2 { f: Box<dyn Iterator<Item: Copy>> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+struct S3 { f: dyn Iterator<Item: 'static> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+
+enum E1 { V(dyn Iterator<Item: Copy>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+enum E3 { V(dyn Iterator<Item: 'static>) }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+
+union U1 { f: dyn Iterator<Item: Copy> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+union U2 { f: Box<dyn Iterator<Item: Copy>> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
+union U3 { f: dyn Iterator<Item: 'static> }
+//~^ associated type bounds are not allowed within structs, enums, or unions
+//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
new file mode 100644
index 0000000000000..7bdd71b8296ff
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -0,0 +1,79 @@
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:8:29
+   |
+LL | struct S1 { f: dyn Iterator<Item: Copy> }
+   |                             ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:11:33
+   |
+LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
+   |                                 ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:14:29
+   |
+LL | struct S3 { f: dyn Iterator<Item: 'static> }
+   |                             ^^^^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:18:26
+   |
+LL | enum E1 { V(dyn Iterator<Item: Copy>) }
+   |                          ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:21:30
+   |
+LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
+   |                              ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:24:26
+   |
+LL | enum E3 { V(dyn Iterator<Item: 'static>) }
+   |                          ^^^^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:28:28
+   |
+LL | union U1 { f: dyn Iterator<Item: Copy> }
+   |                            ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:31:32
+   |
+LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
+   |                                ^^^^^^^^^^
+
+error: associated type bounds are not allowed within structs, enums, or unions
+  --> $DIR/inside-adt.rs:34:28
+   |
+LL | union U3 { f: dyn Iterator<Item: 'static> }
+   |                            ^^^^^^^^^^^^^
+
+error[E0601]: `main` function not found in crate `inside_adt`
+   |
+   = note: consider adding a `main` function to `$DIR/inside-adt.rs`
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: could not find defining uses
+
+error: aborting due to 19 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/associated-type-bounds/lcsit.rs b/src/test/ui/associated-type-bounds/lcsit.rs
new file mode 100644
index 0000000000000..85b6e804b4ef6
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/lcsit.rs
@@ -0,0 +1,78 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(impl_trait_in_bindings)]
+
+#![allow(non_upper_case_globals)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+#[derive(Copy, Clone)]
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
+
+const cdef_et1: impl Copy + Tr1<As1: Copy> = {
+    let x: impl Copy + Tr1<As1: Copy> = S1;
+    x
+};
+static sdef_et1: impl Copy + Tr1<As1: Copy> = cdef_et1;
+pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
+
+const cdef_et2: impl Tr1<As1: 'static> = {
+    let x: impl Tr1<As1: 'static> = S1;
+    x
+};
+static sdef_et2: impl Tr1<As1: 'static> = cdef_et2;
+pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
+
+const cdef_et3: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(&self) -> Self::As1 { 0..10 }
+    };
+    let x: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = A;
+    x
+};
+pub fn use_et3() {
+    let _0 = cdef_et3.mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+const cdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(&self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    let x: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = A;
+    x
+};
+
+static sdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = cdef_et4;
+pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
new file mode 100644
index 0000000000000..25c2c2916f3bc
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
@@ -0,0 +1,25 @@
+// compile-fail
+
+#![feature(associated_type_bounds)]
+
+use std::fmt::Debug;
+
+trait Lam<Binder> { type App; }
+
+fn nested_bounds<_0, _1, _2, D>()
+where
+    D: Clone + Iterator<Item: Send + for<'a> Iterator<Item: for<'b> Lam<&'a &'b u8, App = _0>>>,
+    //~^ ERROR nested quantification of lifetimes [E0316]
+    _0: Debug,
+{}
+
+fn nested_bounds_desugared<_0, _1, _2, D>()
+where
+    D: Clone + Iterator<Item = _2>,
+    _2: Send + for<'a> Iterator,
+    for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
+    //~^ ERROR nested quantification of lifetimes [E0316]
+    _0: Debug,
+{}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
new file mode 100644
index 0000000000000..44fa9e89d3502
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
@@ -0,0 +1,9 @@
+error[E0316]: nested quantification of lifetimes
+  --> $DIR/nested-lifetime-bounds.rs:20:37
+   |
+LL |     for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0316`.
diff --git a/src/test/ui/associated-type-bounds/rpit.rs b/src/test/ui/associated-type-bounds/rpit.rs
new file mode 100644
index 0000000000000..7b640d5a457df
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/rpit.rs
@@ -0,0 +1,64 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+use std::ops::Add;
+
+trait Tr1 { type As1; fn mk(self) -> Self::As1; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+
+fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
+fn assert_static<T: 'static>(_: T) {}
+fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
+
+fn def_et1() -> impl Tr1<As1: Copy> { S1 }
+pub fn use_et1() { assert_copy(def_et1().mk()); }
+
+fn def_et2() -> impl Tr1<As1: 'static> { S1 }
+pub fn use_et2() { assert_static(def_et2().mk()); }
+
+fn def_et3() -> impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> {
+    struct A;
+    impl Tr1 for A {
+        type As1 = core::ops::Range<u8>;
+        fn mk(self) -> Self::As1 { 0..10 }
+    };
+    A
+}
+
+pub fn use_et3() {
+    let _0 = def_et3().mk().clone();
+    let mut s = 0u8;
+    for _1 in _0 {
+        let _2 = _1 + 1u8;
+        s += _2.into();
+    }
+    assert_eq!(s, (0..10).map(|x| x + 1).sum());
+}
+
+fn def_et4() -> impl Tr1<As1: for<'a> Tr2<'a>> {
+    #[derive(Copy, Clone)]
+    struct A;
+    impl Tr1 for A {
+        type As1 = A;
+        fn mk(self) -> A { A }
+    }
+    impl<'a> Tr2<'a> for A {
+        fn tr2(self) -> &'a Self { &A }
+    }
+    A
+}
+
+pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
+
+fn main() {
+    let _ = use_et1();
+    let _ = use_et2();
+    let _ = use_et3();
+    let _ = use_et4();
+}
diff --git a/src/test/ui/associated-type-bounds/struct-bounds.rs b/src/test/ui/associated-type-bounds/struct-bounds.rs
new file mode 100644
index 0000000000000..2d189cd66724a
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/struct-bounds.rs
@@ -0,0 +1,115 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 {}
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 {}
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+struct St1<T: Tr1<As1: Tr2>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+fn unwrap_1_st1<T: Tr1<As1: Tr2>>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2) {
+    (x.outest, x.outer, x.inner)
+}
+
+fn unwrap_2_st1<T>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    unwrap_1_st1(x)
+}
+
+struct St2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+struct St3<T: Tr1<As1: 'static>> {
+    outest: T,
+    outer: &'static T::As1,
+}
+
+struct St4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+struct St5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+struct St6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    f0: T,
+    f1: <T::As1 as Tr2>::As2,
+    f2: &'static T::As1,
+    f3: <T::As1 as Tr5>::As5,
+}
+
+struct St7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    f0: &'a T,
+    f1: &'b <T::As1 as Tr2>::As2,
+}
+
+fn _use_st7<'a, 'b, T>(x: St7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    let _: &'a T = &x.f0;
+}
+
+struct StSelf<T> where Self: Tr1<As1: Tr2> {
+    f2: <<Self as Tr1>::As1 as Tr2>::As2,
+}
+
+impl Tr1 for StSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    let st1 = St1 { outest: "foo", outer: true, inner: 42u8 };
+    assert_eq!(("foo", true, 42), unwrap_1_st1(st1));
+
+    let _ = St2 { outest: "foo", outer: true, inner: 42u8 };
+
+    let _ = St3 { outest: "foo", outer: &true };
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let st4 = St4::<()> { f1: &f1.0, f2: &f2.0, };
+    assert_eq!((&1, &2), (st4.f1, st4.f2));
+
+    // FIXME: requires lazy normalization.
+    /*
+    let f1 = (1,);
+    let f2 = (2,);
+    let st5 = St5::<()> { f1: &f1.0, f2: &f2.0, };
+    assert_eq!((&1, &2), (st5.f1, st5.f2));
+    */
+
+    let st6 = St6 { f0: "bar", f1: 24u8, f2: &true, f3: 12u16, };
+    assert_eq!(("bar", 24, &true, 12), (st6.f0, st6.f1, st6.f2, st6.f3));
+
+    let stself = StSelf::<&'static str> { f2: 42u8 };
+    assert_eq!(stself.f2, 42u8);
+}
diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs
new file mode 100644
index 0000000000000..a9081d50cfc5d
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/trait-params.rs
@@ -0,0 +1,116 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+use std::iter::Once;
+use std::ops::Range;
+
+pub trait Three { type A; type B; type C; }
+pub fn assert_three<T: ?Sized + Three>() {}
+pub fn assert_iterator<T: Iterator>() {}
+pub fn assert_copy<T: Copy>() {}
+pub fn assert_static<T: 'static>() {}
+pub fn assert_send<T: Send>() {}
+pub fn assert_forall_into<T: for<'a> Into<&'a u8>>() {}
+
+struct A; struct B;
+impl<'a> Into<&'a u8> for A { fn into(self) -> &'a u8 { &0 } }
+impl Three for B { type A = Range<u8>; type B = Range<u8>; type C = Range<u8>; }
+
+trait Case1<A, B, C, D, E>
+where
+    A: Iterator<Item: Copy>,
+    B: Iterator<Item: 'static>,
+    C: Iterator<Item: 'static + Copy + Send>,
+    D: Iterator<Item: for<'a> Into<&'a u8>>,
+    E: Three<A: Iterator<Item: Copy>, B: Iterator<Item: Copy>, C: Iterator<Item: Copy>>,
+    Self: Three<A: 'static, B: Copy, C: Send>,
+{
+    fn _a() {
+        assert_iterator::<A>();
+        assert_copy::<A::Item>();
+    }
+    fn _b() {
+        assert_iterator::<B>();
+        assert_static::<B::Item>();
+    }
+    fn _c() {
+        assert_iterator::<C>();
+        assert_copy::<C::Item>();
+        assert_static::<C::Item>();
+        assert_send::<C::Item>();
+    }
+    fn _d() {
+        assert_iterator::<D>();
+        assert_forall_into::<D::Item>();
+    }
+    fn _e() {
+        assert_three::<E>();
+        assert_iterator::<E::A>();
+        assert_iterator::<E::B>();
+        assert_iterator::<E::C>();
+        assert_copy::<<E::A as Iterator>::Item>();
+        assert_copy::<<E::B as Iterator>::Item>();
+        assert_copy::<<E::C as Iterator>::Item>();
+    }
+    fn _self() {
+        assert_three::<Self>();
+        assert_copy::<Self::B>();
+        assert_static::<Self::A>();
+        assert_send::<Self::C>();
+    }
+}
+
+struct DataCase1;
+impl Three for DataCase1 { type A = u8; type B = u8; type C = u8; }
+impl Case1<Range<u8>, Range<u8>, Range<u8>, Once<A>, B> for DataCase1 {}
+
+trait Case2<
+    A: Iterator<Item: Copy>,
+    B: Iterator<Item: 'static>,
+    C: Iterator<Item: 'static + Copy + Send>,
+    D: Iterator<Item: for<'a> Into<&'a u8>>,
+    E: Three<A: Iterator<Item: Copy>, B: Iterator<Item: Copy>, C: Iterator<Item: Copy>>,
+>:
+    Three<A: 'static, B: Copy, C: Send>
+{
+    fn _a() {
+        assert_iterator::<A>();
+        assert_copy::<A::Item>();
+    }
+    fn _b() {
+        assert_iterator::<B>();
+        assert_static::<B::Item>();
+    }
+    fn _c() {
+        assert_iterator::<C>();
+        assert_copy::<C::Item>();
+        assert_static::<C::Item>();
+        assert_send::<C::Item>();
+    }
+    fn _d() {
+        assert_iterator::<D>();
+        assert_forall_into::<D::Item>();
+    }
+    fn _e() {
+        assert_three::<E>();
+        assert_iterator::<E::A>();
+        assert_iterator::<E::B>();
+        assert_iterator::<E::C>();
+        assert_copy::<<E::A as Iterator>::Item>();
+        assert_copy::<<E::B as Iterator>::Item>();
+        assert_copy::<<E::C as Iterator>::Item>();
+    }
+    fn _self() {
+        assert_three::<Self>();
+        assert_copy::<Self::B>();
+        assert_static::<Self::A>();
+        assert_send::<Self::C>();
+    }
+}
+
+struct DataCase2;
+impl Three for DataCase2 { type A = u8; type B = u8; type C = u8; }
+impl Case2<Range<u8>, Range<u8>, Range<u8>, Once<A>, B> for DataCase2 {}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/type-alias.rs b/src/test/ui/associated-type-bounds/type-alias.rs
new file mode 100644
index 0000000000000..1602fdd275a2e
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/type-alias.rs
@@ -0,0 +1,19 @@
+// compile-pass
+
+#![feature(associated_type_bounds)]
+
+type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+type _TaWhere2<T> where T: Iterator<Item: 'static> = T;
+type _TaWhere3<T> where T: Iterator<Item: 'static> = T;
+type _TaWhere4<T> where T: Iterator<Item: 'static + Copy + Send> = T;
+type _TaWhere5<T> where T: Iterator<Item: for<'a> Into<&'a u8>> = T;
+type _TaWhere6<T> where T: Iterator<Item: Iterator<Item: Copy>> = T;
+
+type _TaInline1<T: Iterator<Item: Copy>> = T;
+type _TaInline2<T: Iterator<Item: 'static>> = T;
+type _TaInline3<T: Iterator<Item: 'static>> = T;
+type _TaInline4<T: Iterator<Item: 'static + Copy + Send>> = T;
+type _TaInline5<T: Iterator<Item: for<'a> Into<&'a u8>>> = T;
+type _TaInline6<T: Iterator<Item: Iterator<Item: Copy>>> = T;
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/type-alias.stderr b/src/test/ui/associated-type-bounds/type-alias.stderr
new file mode 100644
index 0000000000000..b93fc393ae32c
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/type-alias.stderr
@@ -0,0 +1,97 @@
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:5:25
+   |
+LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(type_alias_bounds)] on by default
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:6:25
+   |
+LL | type _TaWhere2<T> where T: Iterator<Item: 'static> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:7:25
+   |
+LL | type _TaWhere3<T> where T: Iterator<Item: 'static> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:8:25
+   |
+LL | type _TaWhere4<T> where T: Iterator<Item: 'static + Copy + Send> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:9:25
+   |
+LL | type _TaWhere5<T> where T: Iterator<Item: for<'a> Into<&'a u8>> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias.rs:10:25
+   |
+LL | type _TaWhere6<T> where T: Iterator<Item: Iterator<Item: Copy>> = T;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:12:20
+   |
+LL | type _TaInline1<T: Iterator<Item: Copy>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:13:20
+   |
+LL | type _TaInline2<T: Iterator<Item: 'static>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:14:20
+   |
+LL | type _TaInline3<T: Iterator<Item: 'static>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:15:20
+   |
+LL | type _TaInline4<T: Iterator<Item: 'static + Copy + Send>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:16:20
+   |
+LL | type _TaInline5<T: Iterator<Item: for<'a> Into<&'a u8>>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias.rs:17:20
+   |
+LL | type _TaInline6<T: Iterator<Item: Iterator<Item: Copy>>> = T;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
new file mode 100644
index 0000000000000..ce482fff401c8
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -0,0 +1,123 @@
+// run-pass
+
+#![feature(associated_type_bounds)]
+#![feature(untagged_unions)]
+
+#![allow(unions_with_drop_fields, unused_assignments)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+trait Tr3 { type As3; }
+trait Tr4<'a> { type As4; }
+trait Tr5 { type As5; }
+
+impl Tr1 for &str { type As1 = bool; }
+impl Tr2 for bool { type As2 = u8; }
+impl Tr3 for u8 { type As3 = fn() -> u8; }
+impl Tr1 for () { type As1 = (usize,); }
+impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
+impl Tr5 for bool { type As5 = u16; }
+
+union Un1<T: Tr1<As1: Tr2>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+union Un2<T: Tr1<As1: Tr2<As2: Tr3>>> {
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+union Un3<T: Tr1<As1: 'static>> {
+    outest: T,
+    outer: &'static T::As1,
+}
+
+union Un4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+union _Un5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
+    f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
+    f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
+}
+
+union Un6<T>
+where
+    T: Tr1<As1: Tr2 + 'static + Tr5>,
+{
+    f0: T,
+    f1: <T::As1 as Tr2>::As2,
+    f2: &'static T::As1,
+    f3: <T::As1 as Tr5>::As5,
+}
+
+union _Un7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
+where
+    T: Tr1<As1: Tr2>,
+{
+    f0: &'a T,
+    f1: &'b <T::As1 as Tr2>::As2,
+}
+
+unsafe fn _use_un7<'a, 'b, T>(x: _Un7<'a, 'b, T>)
+where
+    T: Tr1,
+    T::As1: Tr2,
+{
+    let _: &'a T = &x.f0;
+}
+
+union UnSelf<T> where Self: Tr1<As1: Tr2> {
+    f0: T,
+    f1: <Self as Tr1>::As1,
+    f2: <<Self as Tr1>::As1 as Tr2>::As2,
+}
+
+impl Tr1 for UnSelf<&'static str> { type As1 = bool; }
+
+fn main() {
+    let mut un1 = Un1 { outest: "foo" };
+    un1 = Un1 { outer: true };
+    assert_eq!(unsafe { un1.outer }, true);
+    un1 = Un1 { inner: 42u8 };
+    assert_eq!(unsafe { un1.inner }, 42u8);
+
+    let mut un2 = Un2 { outest: "bar" };
+    assert_eq!(unsafe { un2.outest }, "bar");
+    un2 = Un2 { outer: true };
+    assert_eq!(unsafe { un2.outer }, true);
+    un2 = Un2 { inner: 42u8 };
+    assert_eq!(unsafe { un2.inner }, 42u8);
+
+    let mut un3 = Un3 { outest: "baz" };
+    assert_eq!(unsafe { un3.outest }, "baz");
+    un3 = Un3 { outer: &true };
+    assert_eq!(unsafe { *un3.outer }, true);
+
+    let f1 = (1,);
+    let f2 = (2,);
+    let mut un4 = Un4::<()> { f1: &f1.0 };
+    assert_eq!(1, unsafe { *un4.f1 });
+    un4 = Un4 { f2: &f2.0 };
+    assert_eq!(2, unsafe { *un4.f2 });
+
+    let mut un6 = Un6 { f0: "bar" };
+    assert_eq!(unsafe { un6.f0 }, "bar");
+    un6 = Un6 { f1: 24u8 };
+    assert_eq!(unsafe { un6.f1 }, 24u8);
+    un6 = Un6 { f2: &true };
+    assert_eq!(unsafe { un6.f2 }, &true);
+    un6 = Un6 { f3: 12u16 };
+    assert_eq!(unsafe { un6.f3 }, 12u16);
+
+    let mut unself = UnSelf::<_> { f0: "selfish" };
+    assert_eq!(unsafe { unself.f0 }, "selfish");
+    unself = UnSelf { f1: true };
+    assert_eq!(unsafe { unself.f1 }, true);
+    unself = UnSelf { f2: 24u8 };
+    assert_eq!(unsafe { unself.f2 }, 24u8);
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
new file mode 100644
index 0000000000000..6b4f5005d48f0
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -0,0 +1,71 @@
+#![feature(untagged_unions)]
+
+trait Tr1 { type As1; }
+trait Tr2 { type As2; }
+
+struct S1;
+#[derive(Copy, Clone)]
+struct S2;
+impl Tr1 for S1 { type As1 = S2; }
+
+trait _Tr3 {
+    type A: Iterator<Item: Copy>;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+    type B: Iterator<Item: 'static>;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+}
+
+struct _St1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+enum _En1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    Outest(T),
+    Outer(T::As1),
+    Inner(<T::As1 as Tr2>::As2),
+}
+
+union _Un1<T: Tr1<As1: Tr2>> {
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    outest: T,
+    outer: T::As1,
+    inner: <T::As1 as Tr2>::As2,
+}
+
+type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+fn _apit(_: impl Tr1<As1: Copy>) {}
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+fn _rpit() -> impl Tr1<As1: Copy> { S1 }
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+
+const _cdef: impl Tr1<As1: Copy> = S1;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+// const _cdef_dyn: &dyn Tr1<As1: Copy> = &S1;
+
+static _sdef: impl Tr1<As1: Copy> = S1;
+//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+// static _sdef_dyn: &dyn Tr1<As1: Copy> = &S1;
+
+fn main() {
+    let _: impl Tr1<As1: Copy> = S1;
+    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
+    // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
+    // let _: &dyn Tr1<As1: Copy> = &S1;
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
new file mode 100644
index 0000000000000..9b83c1cfb33d1
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -0,0 +1,132 @@
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:12:22
+   |
+LL |     type A: Iterator<Item: Copy>;
+   |                      ^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:15:22
+   |
+LL |     type B: Iterator<Item: 'static>;
+   |                      ^^^^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:19:20
+   |
+LL | struct _St1<T: Tr1<As1: Tr2>> {
+   |                    ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:26:18
+   |
+LL | enum _En1<T: Tr1<As1: Tr2>> {
+   |                  ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:33:19
+   |
+LL | union _Un1<T: Tr1<As1: Tr2>> {
+   |                   ^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:40:37
+   |
+LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
+   |                                     ^^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:43:22
+   |
+LL | fn _apit(_: impl Tr1<As1: Copy>) {}
+   |                      ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:45:26
+   |
+LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
+   |                          ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:48:24
+   |
+LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
+   |                        ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:50:31
+   |
+LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
+   |                               ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:53:23
+   |
+LL | const _cdef: impl Tr1<As1: Copy> = S1;
+   |                       ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:59:24
+   |
+LL | static _sdef: impl Tr1<As1: Copy> = S1;
+   |                        ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable (see issue #52662)
+  --> $DIR/feature-gate-associated_type_bounds.rs:66:21
+   |
+LL |     let _: impl Tr1<As1: Copy> = S1;
+   |                     ^^^^^^^^^
+   |
+   = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:53:14
+   |
+LL | const _cdef: impl Tr1<As1: Copy> = S1;
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:59:15
+   |
+LL | static _sdef: impl Tr1<As1: Copy> = S1;
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
+  --> $DIR/feature-gate-associated_type_bounds.rs:66:12
+   |
+LL |     let _: impl Tr1<As1: Copy> = S1;
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
+
+error: aborting due to 16 previous errors
+
+Some errors occurred: E0562, E0658.
+For more information about an error, try `rustc --explain E0562`.
diff --git a/src/test/ui/type/type-alias-bounds.stderr b/src/test/ui/type/type-alias-bounds.stderr
index c0ff56d5ec038..177e5f893ed66 100644
--- a/src/test/ui/type/type-alias-bounds.stderr
+++ b/src/test/ui/type/type-alias-bounds.stderr
@@ -1,13 +1,3 @@
-warning: duplicate auto trait `::marker[0]::Send[0]` found in type parameter bounds
-  --> $DIR/type-alias-bounds.rs:8:14
-   |
-LL | type SVec<T: Send + Send> = Vec<T>;
-   |              ^^^^   ^^^^ subsequent use of auto trait
-   |              |
-   |              first use of auto trait
-   |
-   = note: #[warn(duplicate_auto_traits_in_bounds)] on by default
-
 warning: bounds on generic parameters are not enforced in type aliases
   --> $DIR/type-alias-bounds.rs:8:14
    |

From a71d55701e303514f936b862ae5cf0c410d2a785 Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Sat, 4 May 2019 16:09:28 +0100
Subject: [PATCH 08/24] Addressed points raised in review.

---
 src/librustc/hir/lowering.rs                  |  15 +-
 src/librustc/hir/map/definitions.rs           |   8 +-
 src/librustc/hir/map/mod.rs                   |  10 +-
 src/librustc/hir/mod.rs                       |   4 +-
 src/librustc/ich/impls_syntax.rs              |   2 +-
 src/librustc/infer/opaque_types/mod.rs        |   9 +-
 src/librustc_interface/util.rs                |  21 +--
 src/librustc_resolve/lib.rs                   |   2 +-
 src/librustc_typeck/astconv.rs                |   6 +-
 src/librustc_typeck/collect.rs                |  15 +-
 src/librustdoc/clean/mod.rs                   |   2 +-
 src/libsyntax_pos/hygiene.rs                  |   4 +-
 .../nested-lifetime-bounds.stderr             |   1 -
 .../associated-types-path-2.stderr            |   2 +-
 .../borrowck/borrowck-closures-two-mut.stderr | 104 ++++++++++--
 src/test/ui/borrowck/borrowck-reinit.stderr   |  16 +-
 .../ui/borrowck/borrowck-storage-dead.stderr  |  12 +-
 src/test/ui/borrowck/immutable-arg.stderr     |  14 +-
 src/test/ui/borrowck/issue-41962.stderr       |  24 ++-
 .../const-param-before-other-params.stderr    |  12 +-
 .../deprecation/deprecation-in-staged-api.rs  |   4 +-
 .../feature-gate-associated_type_bounds.rs    |  27 +--
 ...feature-gate-associated_type_bounds.stderr |  55 +++---
 .../yield-while-local-borrowed.stderr         |  32 +++-
 src/test/ui/indexing-requires-a-uint.stderr   |   2 +-
 .../integer-literal-suffix-inference.stderr   |  36 ++--
 src/test/ui/issues/issue-13359.stderr         |   4 +-
 src/test/ui/issues/issue-31910.stderr         |   2 +-
 src/test/ui/issues/issue-45697-1.stderr       |  14 +-
 src/test/ui/issues/issue-45697.stderr         |  14 +-
 src/test/ui/issues/issue-46471-1.stderr       |  17 +-
 src/test/ui/issues/issue-46471.stderr         |  20 ++-
 src/test/ui/issues/issue-46472.stderr         |  24 ++-
 .../liveness-assign-imm-local-notes.stderr    |  51 ++++--
 ...od-ambig-one-trait-unknown-int-type.stderr |   2 +-
 .../ui/mismatched_types/issue-26480.stderr    |   2 +-
 .../ui/moves/moves-based-on-type-tuple.stderr |  16 +-
 src/test/ui/nll/get_default.stderr            |  58 +++++--
 .../ui/nll/loan_ends_mid_block_pair.stderr    |  60 ++++++-
 .../ui/nll/loan_ends_mid_block_vec.stderr     |  88 +++++++++-
 .../nll/region-ends-after-if-condition.stderr |  32 +++-
 src/test/ui/nll/return_from_loop.stderr       |  32 +++-
 src/test/ui/numeric/const-scope.stderr        |   2 +-
 src/test/ui/numeric/len.stderr                |   2 +-
 src/test/ui/numeric/numeric-cast-2.stderr     |   6 +-
 src/test/ui/numeric/numeric-cast.stderr       | 156 +++++++++---------
 src/test/ui/pub/pub-restricted.stderr         |  19 +--
 src/test/ui/repeat_count.stderr               |   4 +-
 src/test/ui/shift-various-bad-types.stderr    |   2 +-
 src/test/ui/symbol-names/basic.stderr         |  14 ++
 src/test/ui/symbol-names/impl1.stderr         |  26 +++
 ...ounds-inconsistent-projection-error.stderr |   2 +-
 .../ui/tutorial-suffix-inference-test.stderr  |   4 +-
 53 files changed, 793 insertions(+), 319 deletions(-)
 create mode 100644 src/test/ui/symbol-names/basic.stderr
 create mode 100644 src/test/ui/symbol-names/impl1.stderr

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index eab01c0bf9924..a49744aa523a9 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1382,12 +1382,12 @@ impl<'a> LoweringContext<'a> {
                 if existential_desugaring {
                     // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
 
-                    let impl_ty_node_id = self.sess.next_node_id();
+                    let impl_trait_node_id = self.sess.next_node_id();
                     let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
                     self.resolver.definitions().create_def_with_parent(
                         parent_def_index,
-                        impl_ty_node_id,
-                        DefPathData::Misc,
+                        impl_trait_node_id,
+                        DefPathData::ImplTrait,
                         DefIndexAddressSpace::High,
                         Mark::root(),
                         DUMMY_SP
@@ -1397,7 +1397,7 @@ impl<'a> LoweringContext<'a> {
                         this.lower_ty(
                             &Ty {
                                 id: this.sess.next_node_id(),
-                                node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()),
+                                node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
                                 span: DUMMY_SP,
                             },
                             itctx,
@@ -1410,9 +1410,8 @@ impl<'a> LoweringContext<'a> {
                     let bounds = self.lower_param_bounds(bounds, itctx);
 
                     let id = self.sess.next_node_id();
-                    let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
                     P(hir::Ty {
-                        hir_id,
+                        hir_id: self.lower_node_id(id),
                         node: hir::TyKind::AssocTyExistential(bounds),
                         span: DUMMY_SP,
                     })
@@ -1423,7 +1422,7 @@ impl<'a> LoweringContext<'a> {
         hir::TypeBinding {
             hir_id: self.lower_node_id(c.id),
             ident: c.ident,
-            ty
+            ty,
             span: c.span,
         }
     }
@@ -1647,7 +1646,7 @@ impl<'a> LoweringContext<'a> {
         // Not tracking it makes lints in rustc and clippy very fragile, as
         // frequently opened issues show.
         let exist_ty_span = self.mark_span_with_reason(
-            CompilerDesugaringKind::ExistentialReturnType,
+            CompilerDesugaringKind::ExistentialType,
             span,
             None,
         );
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index b01eed8f6609d..3edd75fb725da 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -276,7 +276,7 @@ pub enum DefPathData {
     // they are treated specially by the `def_path` function.
     /// The crate root (marker)
     CrateRoot,
-    // Catch-all for random DefId things like DUMMY_NODE_ID
+    // Catch-all for random DefId things like `DUMMY_NODE_ID`
     Misc,
     // Different kinds of items and item-like things:
     /// An impl
@@ -298,9 +298,9 @@ pub enum DefPathData {
     AnonConst,
     /// An `impl Trait` type node
     ImplTrait,
-    /// GlobalMetaData identifies a piece of crate metadata that is global to
-    /// a whole crate (as opposed to just one item). GlobalMetaData components
-    /// are only supposed to show up right below the crate root.
+    /// Identifies a piece of crate metadata that is global to a whole crate
+    /// (as opposed to just one item). `GlobalMetaData` components are only
+    /// supposed to show up right below the crate root.
     GlobalMetaData(InternedString),
 }
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index cdbeb8a4a545d..978a5556d31bf 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -842,7 +842,7 @@ impl<'hir> Map<'hir> {
     }
 
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
-    pub fn get_enclosing_scope(&self, id: HirId) -> Option<HirId> {
+    pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
         self.walk_parent_nodes(hir_id, |node| match *node {
             Node::Item(i) => {
                 match i.node {
@@ -880,14 +880,14 @@ impl<'hir> Map<'hir> {
     }
 
     /// Returns the defining scope for an existential type definition.
-    pub fn get_defining_scope(&self, id: NodeId) -> Option<NodeId> {
+    pub fn get_defining_scope(&self, id: HirId) -> Option<HirId> {
         let mut scope = id;
         loop {
             scope = self.get_enclosing_scope(scope)?;
-            if scope == CRATE_NODE_ID {
-                return Some(CRATE_NODE_ID);
+            if scope == CRATE_HIR_ID {
+                return Some(CRATE_HIR_ID);
             }
-            match self.get(scope) {
+            match self.get_by_hir_id(scope) {
                 Node::Item(i) => {
                     match i.node {
                         ItemKind::Existential(ExistTy { impl_trait_fn: None, .. }) => {}
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 20968ec6a63be..f884651e8be32 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1780,7 +1780,7 @@ pub struct ImplItem {
     pub span: Span,
 }
 
-/// Represents different contents within `impl`s
+/// Represents different contents within `impl`s.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum ImplItemKind {
     /// An associated constant of the given type, set to the constant result
@@ -1794,7 +1794,7 @@ pub enum ImplItemKind {
     Existential(GenericBounds),
 }
 
-// Bind a type to an associated type: `A=Foo`.
+// Bind a type to an associated type (`A = Foo`).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct TypeBinding {
     pub hir_id: HirId,
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index af53f686ae548..0cdd9a863ccb8 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -408,7 +408,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
     Async,
     Await,
     QuestionMark,
-    ExistentialReturnType,
+    ExistentialType,
     ForLoop,
     TryBlock
 });
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 2127fbbd56e93..50f85ea7770a4 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -953,14 +953,13 @@ pub fn may_define_existential_type(
     );
 
     // Named existential types can be defined by any siblings or children of siblings.
-    let scope_node_id = tcx.hir()
-        .get_defining_scope(tcx.hir().hir_to_node_id(opaque_hir_id))
+    let scope = tcx.hir()
+        .get_defining_scope(opaque_hir_id)
         .expect("could not get defining scope");
-    let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
     // We walk up the node tree until we hit the root or the scope of the opaque type.
-    while hir_id != scope_id && hir_id != hir::CRATE_HIR_ID {
+    while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
         hir_id = tcx.hir().get_parent_item(hir_id);
     }
     // Syntactically, we are allowed to define the concrete type if:
-    hir_id == scope_id
+    hir_id == scope
 }
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index fe24eab9f4439..f4f7456a97ad6 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -716,23 +716,14 @@ impl<'a> ReplaceBodyWithLoop<'a> {
                                     ast::GenericArg::Type(ty) => Some(ty),
                                     _ => None,
                                 });
-                                let any_assoc_ty_bounds = data.constraints.iter().any(|c| {
-                                    if let ast::AssocTyConstraintKind::Bound { .. } = c.kind {
-                                        true
-                                    } else {
-                                        false
-                                    }
-                                });
-                                any_assoc_ty_bounds ||
                                 any_involves_impl_trait(types.into_iter()) ||
-                                any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
-                                    if let ast::AssocTyConstraintKind::Equality { ref ty }
-                                            = c.kind {
-                                        Some(ty)
-                                    } else {
-                                        None
+                                data.constraints.iter().any(|c| {
+                                    match c.kind {
+                                        ast::AssocTyConstraintKind::Bound { .. } => true,
+                                        ast::AssocTyConstraintKind::Equality { ref ty } =>
+                                            involves_impl_trait(ty),
                                     }
-                                }))
+                                })
                             },
                             Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter()) ||
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 61a860aef8597..18f3c0285c210 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2533,7 +2533,7 @@ impl<'a> Resolver<'a> {
                 self.with_current_self_item(item, |this| {
                     this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
                         let item_def_id = this.definitions.local_def_id(item.id);
-                        this.with_self_rib(Def::SelfTy(Some(item_def_id), None), |this| {
+                        this.with_self_rib(Res::SelfTy(Some(item_def_id), None), |this| {
                             visit::walk_item(this, item)
                         })
                     })
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5ddb2c974ac02..e37ad77b086fd 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -764,7 +764,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let mut dup_bindings = FxHashMap::default();
         for binding in &assoc_bindings {
             // Specify type to assert that error was already reported in `Err` case.
-            let _ =
+            let _: Result<_, ErrorReported> =
                 self.add_predicates_for_ast_type_binding(
                     trait_ref.hir_ref_id,
                     poly_trait_ref,
@@ -933,8 +933,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 
     /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped
-    /// `Ty` or a region) to ty's notion of ty param bounds, which can either be user-defined traits
-    /// or the built-in trait `Send`.
+    /// `Ty` or a region) to ty's notion of ty param bounds (which can either be user-defined traits
+    /// or the built-in trait `Sized`).
     pub fn compute_bounds(&self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound],
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 90ab596363bff..2751cd0a37ec0 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1650,24 +1650,23 @@ fn find_existential_constraints<'a, 'tcx>(
         }
     }
 
-    let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
-    let scope_node_id = tcx.hir()
-        .get_defining_scope(node_id)
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    let scope = tcx.hir()
+        .get_defining_scope(hir_id)
         .expect("could not get defining scope");
-    let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
     let mut locator = ConstraintLocator {
         def_id,
         tcx,
         found: None,
     };
 
-    debug!("find_existential_constraints: scope_id={:?}", scope_id);
+    debug!("find_existential_constraints: scope={:?}", scope);
 
-    if scope_id == hir::CRATE_HIR_ID {
+    if scope == hir::CRATE_HIR_ID {
         intravisit::walk_crate(&mut locator, tcx.hir().krate());
     } else {
-        debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope_id));
-        match tcx.hir().get_by_hir_id(scope_id) {
+        debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope));
+        match tcx.hir().get_by_hir_id(scope) {
             Node::Item(ref it) => intravisit::walk_item(&mut locator, it),
             Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
             Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 161e426604e94..af283e6c0bc6f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2445,7 +2445,7 @@ pub struct PolyTrait {
 
 /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
 /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
-/// importanntly, it does not preserve mutability or boxes.
+/// importantly, it does not preserve mutability or boxes.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub enum Type {
     /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 213993996a63c..b827416ab53c2 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -714,7 +714,7 @@ pub enum CompilerDesugaringKind {
     /// Desugaring of an `impl Trait` in return type position
     /// to an `existential type Foo: Trait;` and replacing the
     /// `impl Trait` with `Foo`.
-    ExistentialReturnType,
+    ExistentialType,
     Async,
     Await,
     ForLoop,
@@ -728,7 +728,7 @@ impl CompilerDesugaringKind {
             CompilerDesugaringKind::Await => "await",
             CompilerDesugaringKind::QuestionMark => "?",
             CompilerDesugaringKind::TryBlock => "try block",
-            CompilerDesugaringKind::ExistentialReturnType => "existential type",
+            CompilerDesugaringKind::ExistentialType => "existential type",
             CompilerDesugaringKind::ForLoop => "for loop",
         })
     }
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
index 44fa9e89d3502..db421e6973d07 100644
--- a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
+++ b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
@@ -6,4 +6,3 @@ LL |     for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0316`.
diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr
index 1405cb1b4736c..c25f12d008703 100644
--- a/src/test/ui/associated-types/associated-types-path-2.stderr
+++ b/src/test/ui/associated-types/associated-types-path-2.stderr
@@ -49,7 +49,7 @@ error[E0308]: mismatched types
    |
 LL |     let _: i32 = f2(2i32);
    |                  ^^^^^^^^ expected i32, found u32
-help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     let _: i32 = f2(2i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
index bffb11640744c..e881201ddfcc0 100644
--- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
@@ -1,5 +1,80 @@
-error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-closures-two-mut.rs:12:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
+  --> $DIR/borrowck-closures-two-mut.rs:14:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 4);
+   |                        -- - previous borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| x = 5);
+   |                        ^^ - borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
+  --> $DIR/borrowck-closures-two-mut.rs:26:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut x));
+   |                        --          - previous borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
+  --> $DIR/borrowck-closures-two-mut.rs:34:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - previous borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut x));
+   |                        ^^          - borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
+  --> $DIR/borrowck-closures-two-mut.rs:42:24
+   |
+LL |     let c1 = to_fn_mut(|| x = 5);
+   |                        -- - previous borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
+   |                        ^^                                  - borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
+  --> $DIR/borrowck-closures-two-mut.rs:55:24
+   |
+LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
+   |                        --           - previous borrow occurs due to use of `x` in closure
+   |                        |
+   |                        first mutable borrow occurs here
+LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
+   |                        ^^           - borrow occurs due to use of `x` in closure
+   |                        |
+   |                        second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
+  --> $DIR/borrowck-closures-two-mut.rs:14:24
    |
 LL |     let c1 = to_fn_mut(|| x = 4);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -9,11 +84,12 @@ LL |     let c2 = to_fn_mut(|| x = 5);
    |                        ^^ - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
+LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-closures-two-mut.rs:23:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
+  --> $DIR/borrowck-closures-two-mut.rs:26:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut x));
    |                        --          - first borrow occurs due to use of `x` in closure
@@ -23,11 +99,12 @@ LL |     let c2 = to_fn_mut(|| set(&mut x));
    |                        ^^          - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
+LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-closures-two-mut.rs:30:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
+  --> $DIR/borrowck-closures-two-mut.rs:34:24
    |
 LL |     let c1 = to_fn_mut(|| x = 5);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -37,11 +114,12 @@ LL |     let c2 = to_fn_mut(|| set(&mut x));
    |                        ^^          - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
+LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-closures-two-mut.rs:37:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
+  --> $DIR/borrowck-closures-two-mut.rs:42:24
    |
 LL |     let c1 = to_fn_mut(|| x = 5);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -51,12 +129,12 @@ LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nes
    |                        ^^                                  - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-LL |
+...
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-closures-two-mut.rs:49:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
+  --> $DIR/borrowck-closures-two-mut.rs:55:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
    |                        --           - first borrow occurs due to use of `x` in closure
@@ -66,10 +144,10 @@ LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
    |                        ^^           - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-LL |
+...
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error: aborting due to 5 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr
index f8f14b6435f08..3618a7cb2cd39 100644
--- a/src/test/ui/borrowck/borrowck-reinit.stderr
+++ b/src/test/ui/borrowck/borrowck-reinit.stderr
@@ -1,5 +1,15 @@
-error[E0382]: use of moved value: `x`
-  --> $DIR/borrowck-reinit.rs:6:16
+error[E0382]: use of moved value: `x` (Ast)
+  --> $DIR/borrowck-reinit.rs:8:16
+   |
+LL |     drop(x);
+   |          - value moved here
+LL |     let _ = (1,x);
+   |                ^ value used here after move
+   |
+   = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x` (Mir)
+  --> $DIR/borrowck-reinit.rs:8:16
    |
 LL |     let mut x = Box::new(0);
    |         ----- move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
@@ -9,6 +19,6 @@ LL |     drop(x);
 LL |     let _ = (1,x);
    |                ^ value used here after move
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr
index 5b9f49c2e7c92..c291ed224eb3c 100644
--- a/src/test/ui/borrowck/borrowck-storage-dead.stderr
+++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr
@@ -1,9 +1,15 @@
-error[E0381]: use of possibly uninitialized variable: `x`
-  --> $DIR/borrowck-storage-dead.rs:16:17
+error[E0381]: use of possibly uninitialized variable: `x` (Ast)
+  --> $DIR/borrowck-storage-dead.rs:18:17
    |
 LL |         let _ = x + 1;
    |                 ^ use of possibly uninitialized `x`
 
-error: aborting due to previous error
+error[E0381]: use of possibly uninitialized variable: `x` (Mir)
+  --> $DIR/borrowck-storage-dead.rs:18:17
+   |
+LL |         let _ = x + 1;
+   |                 ^ use of possibly uninitialized `x`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/immutable-arg.stderr b/src/test/ui/borrowck/immutable-arg.stderr
index 7255ca327e753..8b21e92666674 100644
--- a/src/test/ui/borrowck/immutable-arg.stderr
+++ b/src/test/ui/borrowck/immutable-arg.stderr
@@ -1,11 +1,19 @@
-error[E0384]: cannot assign to immutable argument `_x`
-  --> $DIR/immutable-arg.rs:2:5
+error[E0384]: cannot assign twice to immutable variable `_x` (Ast)
+  --> $DIR/immutable-arg.rs:4:5
+   |
+LL | fn foo(_x: u32) {
+   |        -- first assignment to `_x`
+LL |     _x = 4;
+   |     ^^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign to immutable argument `_x` (Mir)
+  --> $DIR/immutable-arg.rs:4:5
    |
 LL | fn foo(_x: u32) {
    |        -- help: make this binding mutable: `mut _x`
 LL |     _x = 4;
    |     ^^^^^^ cannot assign to immutable argument
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr
index 422d1605aa46b..fd4d318b5ddf1 100644
--- a/src/test/ui/borrowck/issue-41962.stderr
+++ b/src/test/ui/borrowck/issue-41962.stderr
@@ -1,11 +1,29 @@
-error[E0382]: use of moved value
-  --> $DIR/issue-41962.rs:5:21
+error[E0382]: use of partially moved value: `maybe` (Ast)
+  --> $DIR/issue-41962.rs:7:30
+   |
+LL |         if let Some(thing) = maybe {
+   |                     -----    ^^^^^ value used here after move
+   |                     |
+   |                     value moved here
+   |
+   = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast)
+  --> $DIR/issue-41962.rs:7:21
+   |
+LL |         if let Some(thing) = maybe {
+   |                     ^^^^^ value moved here in previous iteration of loop
+   |
+   = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value (Mir)
+  --> $DIR/issue-41962.rs:7:21
    |
 LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 33f981d1eba9b..78f129e79ea24 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -4,17 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error: lifetime parameters must be declared prior to const parameters
+error: type parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:4:21
    |
-LL | fn bar<const X: (), 'a>(_: &'a ()) {
-   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
+LL | fn foo<const X: (), T>(_: &T) {
+   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
 
-error: type parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:8:21
    |
-LL | fn foo<const X: (), T>(_: &T) {
-   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
+LL | fn bar<const X: (), 'a>(_: &'a ()) {
+   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.rs b/src/test/ui/deprecation/deprecation-in-staged-api.rs
index bcc17c789f551..f667de83b56d4 100644
--- a/src/test/ui/deprecation/deprecation-in-staged-api.rs
+++ b/src/test/ui/deprecation/deprecation-in-staged-api.rs
@@ -1,8 +1,8 @@
-// #[deprecated] can't be used in staged api
+// #[deprecated] cannot be used in staged API
 
 #![feature(staged_api)]
 
 #![stable(feature = "stable_test_feature", since = "1.0.0")]
 
 #[deprecated]
-fn main() { } //~ERROR `#[deprecated]` cannot be used in staged api
+fn main() { } //~ ERROR `#[deprecated]` cannot be used in staged API
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
index 6b4f5005d48f0..3d75251e15616 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -10,61 +10,62 @@ impl Tr1 for S1 { type As1 = S2; }
 
 trait _Tr3 {
     type A: Iterator<Item: Copy>;
-    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    //~^ ERROR associated type bounds are unstable
 
     type B: Iterator<Item: 'static>;
-    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    //~^ ERROR associated type bounds are unstable
 }
 
 struct _St1<T: Tr1<As1: Tr2>> {
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
     outest: T,
     outer: T::As1,
     inner: <T::As1 as Tr2>::As2,
 }
 
 enum _En1<T: Tr1<As1: Tr2>> {
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
     Outest(T),
     Outer(T::As1),
     Inner(<T::As1 as Tr2>::As2),
 }
 
 union _Un1<T: Tr1<As1: Tr2>> {
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
     outest: T,
     outer: T::As1,
     inner: <T::As1 as Tr2>::As2,
 }
 
 type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 
 fn _apit(_: impl Tr1<As1: Copy>) {}
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 
 fn _rpit() -> impl Tr1<As1: Copy> { S1 }
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
+
 fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 
 const _cdef: impl Tr1<As1: Copy> = S1;
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
 // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
 // const _cdef_dyn: &dyn Tr1<As1: Copy> = &S1;
 
 static _sdef: impl Tr1<As1: Copy> = S1;
-//~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+//~^ ERROR associated type bounds are unstable
 //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
 // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
 // static _sdef_dyn: &dyn Tr1<As1: Copy> = &S1;
 
 fn main() {
     let _: impl Tr1<As1: Copy> = S1;
-    //~^ ERROR associated type bounds are unstable (see issue #52662) [E0658]
+    //~^ ERROR associated type bounds are unstable
     //~| ERROR `impl Trait` not allowed outside of function and inherent method return types [E0562]
     // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
     // let _: &dyn Tr1<As1: Copy> = &S1;
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
index 9b83c1cfb33d1..702f61262df69 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -1,109 +1,122 @@
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:12:22
    |
 LL |     type A: Iterator<Item: Copy>;
    |                      ^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:15:22
    |
 LL |     type B: Iterator<Item: 'static>;
    |                      ^^^^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:19:20
    |
 LL | struct _St1<T: Tr1<As1: Tr2>> {
    |                    ^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:26:18
    |
 LL | enum _En1<T: Tr1<As1: Tr2>> {
    |                  ^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:33:19
    |
 LL | union _Un1<T: Tr1<As1: Tr2>> {
    |                   ^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:40:37
    |
 LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
    |                                     ^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:43:22
    |
 LL | fn _apit(_: impl Tr1<As1: Copy>) {}
    |                      ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:45:26
    |
 LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
    |                          ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
+error[E0658]: associated type bounds are unstable
   --> $DIR/feature-gate-associated_type_bounds.rs:48:24
    |
 LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
    |                        ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
-  --> $DIR/feature-gate-associated_type_bounds.rs:50:31
+error[E0658]: associated type bounds are unstable
+  --> $DIR/feature-gate-associated_type_bounds.rs:51:31
    |
 LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
    |                               ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
-  --> $DIR/feature-gate-associated_type_bounds.rs:53:23
+error[E0658]: associated type bounds are unstable
+  --> $DIR/feature-gate-associated_type_bounds.rs:54:23
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |                       ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
-  --> $DIR/feature-gate-associated_type_bounds.rs:59:24
+error[E0658]: associated type bounds are unstable
+  --> $DIR/feature-gate-associated_type_bounds.rs:60:24
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |                        ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
-error[E0658]: associated type bounds are unstable (see issue #52662)
-  --> $DIR/feature-gate-associated_type_bounds.rs:66:21
+error[E0658]: associated type bounds are unstable
+  --> $DIR/feature-gate-associated_type_bounds.rs:67:21
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |                     ^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52662
    = help: add #![feature(associated_type_bounds)] to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:53:14
+  --> $DIR/feature-gate-associated_type_bounds.rs:54:14
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |              ^^^^^^^^^^^^^^^^^^^
@@ -111,7 +124,7 @@ LL | const _cdef: impl Tr1<As1: Copy> = S1;
    = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:59:15
+  --> $DIR/feature-gate-associated_type_bounds.rs:60:15
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |               ^^^^^^^^^^^^^^^^^^^
@@ -119,7 +132,7 @@ LL | static _sdef: impl Tr1<As1: Copy> = S1;
    = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:66:12
+  --> $DIR/feature-gate-associated_type_bounds.rs:67:12
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |            ^^^^^^^^^^^^^^^^^^^
@@ -128,5 +141,5 @@ LL |     let _: impl Tr1<As1: Copy> = S1;
 
 error: aborting due to 16 previous errors
 
-Some errors occurred: E0562, E0658.
+Some errors have detailed explanations: E0562, E0658.
 For more information about an error, try `rustc --explain E0562`.
diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr
index c1513ef9b7157..56f425b7e70a0 100644
--- a/src/test/ui/generator/yield-while-local-borrowed.stderr
+++ b/src/test/ui/generator/yield-while-local-borrowed.stderr
@@ -1,21 +1,39 @@
-error[E0626]: borrow may still be in use when generator yields
-  --> $DIR/yield-while-local-borrowed.rs:13:17
+error[E0626]: borrow may still be in use when generator yields (Ast)
+  --> $DIR/yield-while-local-borrowed.rs:15:22
+   |
+LL |         let a = &mut 3;
+   |                      ^
+...
+LL |         yield();
+   |         ------- possible yield occurs here
+
+error[E0626]: borrow may still be in use when generator yields (Ast)
+  --> $DIR/yield-while-local-borrowed.rs:43:22
+   |
+LL |             let b = &a;
+   |                      ^
+...
+LL |             yield();
+   |             ------- possible yield occurs here
+
+error[E0626]: borrow may still be in use when generator yields (Mir)
+  --> $DIR/yield-while-local-borrowed.rs:15:17
    |
 LL |         let a = &mut 3;
    |                 ^^^^^^
-LL |
+...
 LL |         yield();
    |         ------- possible yield occurs here
 
-error[E0626]: borrow may still be in use when generator yields
-  --> $DIR/yield-while-local-borrowed.rs:40:21
+error[E0626]: borrow may still be in use when generator yields (Mir)
+  --> $DIR/yield-while-local-borrowed.rs:43:21
    |
 LL |             let b = &a;
    |                     ^^
-LL |
+...
 LL |             yield();
    |             ------- possible yield occurs here
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr
index 3300db58d44c3..9dafe1c24f1c2 100644
--- a/src/test/ui/indexing-requires-a-uint.stderr
+++ b/src/test/ui/indexing-requires-a-uint.stderr
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
    |
 LL |     bar::<isize>(i);  // i should not be re-coerced back to an isize
    |                  ^ expected isize, found usize
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     bar::<isize>(i.try_into().unwrap());  // i should not be re-coerced back to an isize
    |                  ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr
index 80b601dc4394b..b5b3f27f0e6cd 100644
--- a/src/test/ui/integer-literal-suffix-inference.stderr
+++ b/src/test/ui/integer-literal-suffix-inference.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a16);
    |           ^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(a16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a32);
    |           ^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(a32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a64);
    |           ^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(a64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(a32);
    |            ^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     id_i16(a32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(a64);
    |            ^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     id_i16(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i32(a64);
    |            ^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     id_i32(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c16);
    |           ^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(c16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,7 +127,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c32);
    |           ^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(c32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -137,7 +137,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c64);
    |           ^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     id_i8(c64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(c32);
    |            ^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     id_i16(c32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(c64);
    |            ^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     id_i16(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -194,7 +194,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i32(c64);
    |            ^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     id_i32(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -231,7 +231,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b16);
    |           ^^^ expected u8, found u16
-help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     id_u8(b16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b32);
    |           ^^^ expected u8, found u32
-help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     id_u8(b32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -251,7 +251,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b64);
    |           ^^^ expected u8, found u64
-help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     id_u8(b64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u16(b32);
    |            ^^^ expected u16, found u32
-help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     id_u16(b32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u16(b64);
    |            ^^^ expected u16, found u64
-help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     id_u16(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -308,7 +308,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u32(b64);
    |            ^^^ expected u32, found u64
-help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     id_u32(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr
index 7cfd754f72d8e..b16b7a5b2cf04 100644
--- a/src/test/ui/issues/issue-13359.stderr
+++ b/src/test/ui/issues/issue-13359.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     foo(1*(1 as isize));
    |         ^^^^^^^^^^^^^^ expected i16, found isize
-help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo((1*(1 as isize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     bar(1*(1 as usize));
    |         ^^^^^^^^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     bar((1*(1 as usize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-31910.stderr b/src/test/ui/issues/issue-31910.stderr
index e7555b958a3d4..8dd9287ffec79 100644
--- a/src/test/ui/issues/issue-31910.stderr
+++ b/src/test/ui/issues/issue-31910.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     X = Trait::Number,
    |         ^^^^^^^^^^^^^ expected isize, found i32
-help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     X = Trait::Number.try_into().unwrap(),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-45697-1.stderr b/src/test/ui/issues/issue-45697-1.stderr
index 30c69f19658c8..854e18003f330 100644
--- a/src/test/ui/issues/issue-45697-1.stderr
+++ b/src/test/ui/issues/issue-45697-1.stderr
@@ -1,4 +1,12 @@
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+  --> $DIR/issue-45697-1.rs:20:9
+   |
+LL |         let z = copy_borrowed_ptr(&mut y);
+   |                                        - borrow of `*y.pointer` occurs here
+LL |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -9,7 +17,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -20,7 +28,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0503, E0506.
 For more information about an error, try `rustc --explain E0503`.
diff --git a/src/test/ui/issues/issue-45697.stderr b/src/test/ui/issues/issue-45697.stderr
index 26749d36f0b7b..01ae416b1cf14 100644
--- a/src/test/ui/issues/issue-45697.stderr
+++ b/src/test/ui/issues/issue-45697.stderr
@@ -1,4 +1,12 @@
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+  --> $DIR/issue-45697.rs:20:9
+   |
+LL |         let z = copy_borrowed_ptr(&mut y);
+   |                                        - borrow of `*y.pointer` occurs here
+LL |         *y.pointer += 1;
+   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -9,7 +17,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -20,7 +28,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0503, E0506.
 For more information about an error, try `rustc --explain E0503`.
diff --git a/src/test/ui/issues/issue-46471-1.stderr b/src/test/ui/issues/issue-46471-1.stderr
index b09f31729a5fd..51026c9f2d834 100644
--- a/src/test/ui/issues/issue-46471-1.stderr
+++ b/src/test/ui/issues/issue-46471-1.stderr
@@ -1,5 +1,16 @@
-error[E0597]: `z` does not live long enough
-  --> $DIR/issue-46471-1.rs:4:9
+error[E0597]: `z` does not live long enough (Ast)
+  --> $DIR/issue-46471-1.rs:6:14
+   |
+LL |         &mut z
+   |              ^ borrowed value does not live long enough
+LL |     };
+   |     - `z` dropped here while still borrowed
+...
+LL | }
+   | - borrowed value needs to live until here
+
+error[E0597]: `z` does not live long enough (Mir)
+  --> $DIR/issue-46471-1.rs:6:9
    |
 LL |         &mut z
    |         ^^^^^^
@@ -9,6 +20,6 @@ LL |         &mut z
 LL |     };
    |     - `z` dropped here while still borrowed
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issues/issue-46471.stderr b/src/test/ui/issues/issue-46471.stderr
index 935414c1f3f9d..90202e307eb11 100644
--- a/src/test/ui/issues/issue-46471.stderr
+++ b/src/test/ui/issues/issue-46471.stderr
@@ -1,9 +1,21 @@
-error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-46471.rs:3:5
+error[E0597]: `x` does not live long enough (Ast)
+  --> $DIR/issue-46471.rs:5:6
+   |
+LL |     &x
+   |      ^ borrowed value does not live long enough
+...
+LL | }
+   | - borrowed value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0515]: cannot return reference to local variable `x` (Mir)
+  --> $DIR/issue-46471.rs:5:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0515`.
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/issues/issue-46472.stderr b/src/test/ui/issues/issue-46472.stderr
index 6e561e03a8b7a..0cc93a081b2af 100644
--- a/src/test/ui/issues/issue-46472.stderr
+++ b/src/test/ui/issues/issue-46472.stderr
@@ -1,5 +1,20 @@
-error[E0515]: cannot return reference to temporary value
-  --> $DIR/issue-46472.rs:2:5
+error[E0597]: borrowed value does not live long enough (Ast)
+  --> $DIR/issue-46472.rs:4:10
+   |
+LL |     &mut 4
+   |          ^ temporary value does not live long enough
+...
+LL | }
+   | - temporary value only lives until here
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:8...
+  --> $DIR/issue-46472.rs:3:8
+   |
+LL | fn bar<'a>() -> &'a mut u32 {
+   |        ^^
+
+error[E0515]: cannot return reference to temporary value (Mir)
+  --> $DIR/issue-46472.rs:4:5
    |
 LL |     &mut 4
    |     ^^^^^-
@@ -7,6 +22,7 @@ LL |     &mut 4
    |     |    temporary value created here
    |     returns a reference to data owned by the current function
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0515`.
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
index c646912d3b679..e15290f0b9ee9 100644
--- a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
@@ -1,5 +1,36 @@
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/liveness-assign-imm-local-notes.rs:10:9
+error[E0384]: cannot assign twice to immutable variable `x` (Ast)
+  --> $DIR/liveness-assign-imm-local-notes.rs:13:9
+   |
+LL |         x = 2;
+   |         ----- first assignment to `x`
+LL |         x = 3;
+   |         ^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x` (Ast)
+  --> $DIR/liveness-assign-imm-local-notes.rs:25:13
+   |
+LL |             x = 2;
+   |             ----- first assignment to `x`
+LL |             x = 3;
+   |             ^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x` (Ast)
+  --> $DIR/liveness-assign-imm-local-notes.rs:35:13
+   |
+LL |             x = 1;
+   |             ^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x` (Ast)
+  --> $DIR/liveness-assign-imm-local-notes.rs:38:13
+   |
+LL |             x = 1;
+   |             ----- first assignment to `x`
+...
+LL |             x = 2;
+   |             ^^^^^ cannot assign twice to immutable variable
+
+error[E0384]: cannot assign twice to immutable variable `x` (Mir)
+  --> $DIR/liveness-assign-imm-local-notes.rs:13:9
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
@@ -9,8 +40,8 @@ LL |         x = 2;
 LL |         x = 3;
    |         ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/liveness-assign-imm-local-notes.rs:21:13
+error[E0384]: cannot assign twice to immutable variable `x` (Mir)
+  --> $DIR/liveness-assign-imm-local-notes.rs:25:13
    |
 LL |         let x;
    |             - help: make this binding mutable: `mut x`
@@ -20,8 +51,8 @@ LL |             x = 2;
 LL |             x = 3;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/liveness-assign-imm-local-notes.rs:30:13
+error[E0384]: cannot assign twice to immutable variable `x` (Mir)
+  --> $DIR/liveness-assign-imm-local-notes.rs:35:13
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
@@ -29,18 +60,18 @@ LL |     let x;
 LL |             x = 1;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/liveness-assign-imm-local-notes.rs:32:13
+error[E0384]: cannot assign twice to immutable variable `x` (Mir)
+  --> $DIR/liveness-assign-imm-local-notes.rs:38:13
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
 ...
 LL |             x = 1;
    |             ----- first assignment to `x`
-LL |         } else {
+...
 LL |             x = 2;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error: aborting due to 4 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index b1bd749bef4a2..49c72a655e57a 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
    |
 LL |     let y: usize = x.foo();
    |                    ^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     let y: usize = x.foo().try_into().unwrap();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index 881d9fd32029e..1a81df8e2c464 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -6,7 +6,7 @@ LL |                   $arr.len() * size_of($arr[0]));
 ...
 LL |     write!(hello);
    |     -------------- in this macro invocation
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |                   ($arr.len() * size_of($arr[0])).try_into().unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr
index 2e1ddbdf57f98..c49dbdab40210 100644
--- a/src/test/ui/moves/moves-based-on-type-tuple.stderr
+++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr
@@ -1,5 +1,15 @@
-error[E0382]: use of moved value: `x`
-  --> $DIR/moves-based-on-type-tuple.rs:4:13
+error[E0382]: use of moved value: `x` (Ast)
+  --> $DIR/moves-based-on-type-tuple.rs:6:13
+   |
+LL |     box (x, x)
+   |          -  ^ value used here after move
+   |          |
+   |          value moved here
+   |
+   = note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x` (Mir)
+  --> $DIR/moves-based-on-type-tuple.rs:6:13
    |
 LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
    |        - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
@@ -8,6 +18,6 @@ LL |     box (x, x)
    |          |
    |          value moved here
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr
index af79771e7e1b9..abb5343845b57 100644
--- a/src/test/ui/nll/get_default.stderr
+++ b/src/test/ui/nll/get_default.stderr
@@ -1,5 +1,41 @@
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:21:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
+  --> $DIR/get_default.rs:23:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
+  --> $DIR/get_default.rs:35:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+LL |             Some(v) => {
+LL |                 map.set(String::new()); // Both AST and MIR error here
+   |                 ^^^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
+  --> $DIR/get_default.rs:41:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:23:17
    |
 LL | fn ok(map: &mut Map) -> &String {
    |            - let's call the lifetime of this reference `'1`
@@ -11,10 +47,10 @@ LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 ...
 LL |                 map.set(String::new()); // Ideally, this would not error.
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^ mutable borrow occurs here
 
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:32:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:35:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -23,13 +59,13 @@ LL |         match map.get() {
    |               --- immutable borrow occurs here
 LL |             Some(v) => {
 LL |                 map.set(String::new()); // Both AST and MIR error here
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
-LL |
+   |                 ^^^ mutable borrow occurs here
+...
 LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
-  --> $DIR/get_default.rs:37:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:41:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -41,8 +77,8 @@ LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 ...
 LL |                 map.set(String::new()); // Ideally, just AST would error here
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^ mutable borrow occurs here
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.stderr b/src/test/ui/nll/loan_ends_mid_block_pair.stderr
index eb8442b31d7c7..85703bda31c4e 100644
--- a/src/test/ui/nll/loan_ends_mid_block_pair.stderr
+++ b/src/test/ui/nll/loan_ends_mid_block_pair.stderr
@@ -1,5 +1,59 @@
-error[E0506]: cannot assign to `data.0` because it is borrowed
-  --> $DIR/loan_ends_mid_block_pair.rs:12:5
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:14:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+LL |     capitalize(c);
+LL |     data.0 = 'e';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:17:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+...
+LL |     data.0 = 'f';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:19:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+...
+LL |     data.0 = 'g';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:28:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+LL |     capitalize(c);
+LL |     data.0 = 'e';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:30:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+...
+LL |     data.0 = 'f';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
+  --> $DIR/loan_ends_mid_block_pair.rs:32:5
+   |
+LL |     let c = &mut data.0;
+   |                  ------ borrow of `data.0` occurs here
+...
+LL |     data.0 = 'g';
+   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+
+error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
+  --> $DIR/loan_ends_mid_block_pair.rs:14:5
    |
 LL |     let c = &mut data.0;
    |             ----------- borrow of `data.0` occurs here
@@ -10,6 +64,6 @@ LL |     data.0 = 'e';
 LL |     capitalize(c);
    |                - borrow later used here
 
-error: aborting due to previous error
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/nll/loan_ends_mid_block_vec.stderr b/src/test/ui/nll/loan_ends_mid_block_vec.stderr
index c0b97bea348c4..a3f1391f00140 100644
--- a/src/test/ui/nll/loan_ends_mid_block_vec.stderr
+++ b/src/test/ui/nll/loan_ends_mid_block_vec.stderr
@@ -1,5 +1,77 @@
-error[E0499]: cannot borrow `data` as mutable more than once at a time
-  --> $DIR/loan_ends_mid_block_vec.rs:11:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:13:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+LL |     capitalize(slice);
+LL |     data.push('d');
+   |     ^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:16:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+...
+LL |     data.push('e');
+   |     ^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:19:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+...
+LL |     data.push('f');
+   |     ^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:29:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+LL |     capitalize(slice);
+LL |     data.push('d');
+   |     ^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:31:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+...
+LL |     data.push('e');
+   |     ^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
+  --> $DIR/loan_ends_mid_block_vec.rs:33:5
+   |
+LL |     let slice = &mut data;
+   |                      ---- first mutable borrow occurs here
+...
+LL |     data.push('f');
+   |     ^^^^ second mutable borrow occurs here
+LL |
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
+  --> $DIR/loan_ends_mid_block_vec.rs:13:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
@@ -10,8 +82,8 @@ LL |     data.push('d');
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error[E0499]: cannot borrow `data` as mutable more than once at a time
-  --> $DIR/loan_ends_mid_block_vec.rs:13:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
+  --> $DIR/loan_ends_mid_block_vec.rs:16:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
@@ -22,18 +94,18 @@ LL |     data.push('e');
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error[E0499]: cannot borrow `data` as mutable more than once at a time
-  --> $DIR/loan_ends_mid_block_vec.rs:15:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
+  --> $DIR/loan_ends_mid_block_vec.rs:19:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
 ...
 LL |     data.push('f');
    |     ^^^^ second mutable borrow occurs here
-LL |
+...
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error: aborting due to 3 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/nll/region-ends-after-if-condition.stderr b/src/test/ui/nll/region-ends-after-if-condition.stderr
index c03e385790616..aa876a0bcb3bf 100644
--- a/src/test/ui/nll/region-ends-after-if-condition.stderr
+++ b/src/test/ui/nll/region-ends-after-if-condition.stderr
@@ -1,15 +1,39 @@
-error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable
-  --> $DIR/region-ends-after-if-condition.rs:26:9
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast)
+  --> $DIR/region-ends-after-if-condition.rs:19:9
+   |
+LL |     let value = &my_struct.field;
+   |                  --------------- immutable borrow occurs here
+LL |     if value.is_empty() {
+LL |         my_struct.field.push_str("Hello, world!");
+   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast)
+  --> $DIR/region-ends-after-if-condition.rs:29:9
+   |
+LL |     let value = &my_struct.field;
+   |                  --------------- immutable borrow occurs here
+LL |     if value.is_empty() {
+LL |         my_struct.field.push_str("Hello, world!");
+   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/region-ends-after-if-condition.rs:29:9
    |
 LL |     let value = &my_struct.field;
    |                 ---------------- immutable borrow occurs here
 LL |     if value.is_empty() {
 LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
 ...
 LL |     drop(value);
    |          ----- immutable borrow later used here
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/return_from_loop.stderr b/src/test/ui/nll/return_from_loop.stderr
index efd56ea2dd542..09882d55cb70e 100644
--- a/src/test/ui/nll/return_from_loop.stderr
+++ b/src/test/ui/nll/return_from_loop.stderr
@@ -1,15 +1,39 @@
-error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time
-  --> $DIR/return_from_loop.rs:20:9
+error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast)
+  --> $DIR/return_from_loop.rs:22:9
+   |
+LL |     let value = &mut my_struct.field;
+   |                      --------------- first mutable borrow occurs here
+LL |     loop {
+LL |         my_struct.field.push_str("Hello, world!");
+   |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast)
+  --> $DIR/return_from_loop.rs:35:9
+   |
+LL |     let value = &mut my_struct.field;
+   |                      --------------- first mutable borrow occurs here
+LL |     loop {
+LL |         my_struct.field.push_str("Hello, world!");
+   |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL | }
+   | - first borrow ends here
+
+error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Mir)
+  --> $DIR/return_from_loop.rs:22:9
    |
 LL |     let value = &mut my_struct.field;
    |                 -------------------- first mutable borrow occurs here
 LL |     loop {
 LL |         my_struct.field.push_str("Hello, world!");
    |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
-LL |
+...
 LL |         value.len();
    |         ----- first borrow later used here
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr
index 3f69bcc7d4a2f..ead3a79da0270 100644
--- a/src/test/ui/numeric/const-scope.stderr
+++ b/src/test/ui/numeric/const-scope.stderr
@@ -37,7 +37,7 @@ error[E0308]: mismatched types
    |
 LL |     let d: i8 = c;
    |                 ^ expected i8, found i32
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     let d: i8 = c.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr
index c767bdd9bd5a5..5a9349b4c0f29 100644
--- a/src/test/ui/numeric/len.stderr
+++ b/src/test/ui/numeric/len.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     test(array.len());
    |          ^^^^^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     test(array.len().try_into().unwrap());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr
index f58389ce96c3b..be4411e630bec 100644
--- a/src/test/ui/numeric/numeric-cast-2.stderr
+++ b/src/test/ui/numeric/numeric-cast-2.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     let x: u16 = foo();
    |                  ^^^^^ expected u16, found i32
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     let x: u16 = foo().try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     let y: i64 = x + x;
    |                  ^^^^^ expected i64, found u16
-help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     let y: i64 = (x + x).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     let z: i32 = x + x;
    |                  ^^^^^ expected i32, found u16
-help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     let z: i32 = (x + x).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr
index e66b83f2b39f5..9e7dcf7e41b55 100644
--- a/src/test/ui/numeric/numeric-cast.stderr
+++ b/src/test/ui/numeric/numeric-cast.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u64);
    |                  ^^^^^ expected usize, found u64
-help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u32);
    |                  ^^^^^ expected usize, found u32
-help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u16);
    |                  ^^^^^ expected usize, found u16
-help: you can convert an `u16` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u8);
    |                  ^^^^ expected usize, found u8
-help: you can convert an `u8` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_isize);
    |                  ^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_isize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i64);
    |                  ^^^^^ expected usize, found i64
-help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i32);
    |                  ^^^^^ expected usize, found i32
-help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i16);
    |                  ^^^^^ expected usize, found i16
-help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i8);
    |                  ^^^^ expected usize, found i8
-help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -93,7 +93,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_usize);
    |                  ^^^^^^^ expected isize, found usize
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_usize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u64);
    |                  ^^^^^ expected isize, found u64
-help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +113,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u32);
    |                  ^^^^^ expected isize, found u32
-help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,7 +123,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u16);
    |                  ^^^^^ expected isize, found u16
-help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u8);
    |                  ^^^^ expected isize, found u8
-help: you can convert an `u8` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,7 +143,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i64);
    |                  ^^^^^ expected isize, found i64
-help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i32);
    |                  ^^^^^ expected isize, found i32
-help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i16);
    |                  ^^^^^ expected isize, found i16
-help: you can convert an `i16` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i8);
    |                  ^^^^ expected isize, found i8
-help: you can convert an `i8` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `isize` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -183,7 +183,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_usize);
    |                ^^^^^^^ expected u64, found usize
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_isize);
    |                ^^^^^^^ expected u64, found isize
-help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -230,7 +230,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i64);
    |                ^^^^^ expected u64, found i64
-help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -240,7 +240,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i32);
    |                ^^^^^ expected u64, found i32
-help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i16);
    |                ^^^^^ expected u64, found i16
-help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +260,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i8);
    |                ^^^^ expected u64, found i8
-help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `u64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_usize);
    |                ^^^^^^^ expected i64, found usize
-help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u64);
    |                ^^^^^ expected i64, found u64
-help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -290,7 +290,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u32);
    |                ^^^^^ expected i64, found u32
-help: you can convert an `u32` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -300,7 +300,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u16);
    |                ^^^^^ expected i64, found u16
-help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -310,7 +310,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u8);
    |                ^^^^ expected i64, found u8
-help: you can convert an `u8` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -320,7 +320,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_isize);
    |                ^^^^^^^ expected i64, found isize
-help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `i64` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -357,7 +357,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_usize);
    |                ^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_u64);
    |                ^^^^^ expected u32, found u64
-help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -395,7 +395,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_isize);
    |                ^^^^^^^ expected u32, found isize
-help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +405,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i64);
    |                ^^^^^ expected u32, found i64
-help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -415,7 +415,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i32);
    |                ^^^^^ expected u32, found i32
-help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -425,7 +425,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i16);
    |                ^^^^^ expected u32, found i16
-help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -435,7 +435,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i8);
    |                ^^^^ expected u32, found i8
-help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `u32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -445,7 +445,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_usize);
    |                ^^^^^^^ expected i32, found usize
-help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -455,7 +455,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u64);
    |                ^^^^^ expected i32, found u64
-help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -465,7 +465,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u32);
    |                ^^^^^ expected i32, found u32
-help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,7 +475,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u16);
    |                ^^^^^ expected i32, found u16
-help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -485,7 +485,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u8);
    |                ^^^^ expected i32, found u8
-help: you can convert an `u8` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -495,7 +495,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_isize);
    |                ^^^^^^^ expected i32, found isize
-help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -505,7 +505,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_i64);
    |                ^^^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -533,7 +533,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_usize);
    |                ^^^^^^^ expected u16, found usize
-help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -543,7 +543,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_u64);
    |                ^^^^^ expected u16, found u64
-help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -553,7 +553,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_u32);
    |                ^^^^^ expected u16, found u32
-help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -572,7 +572,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_isize);
    |                ^^^^^^^ expected u16, found isize
-help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -582,7 +582,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i64);
    |                ^^^^^ expected u16, found i64
-help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -592,7 +592,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i32);
    |                ^^^^^ expected u16, found i32
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -602,7 +602,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i16);
    |                ^^^^^ expected u16, found i16
-help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -612,7 +612,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i8);
    |                ^^^^ expected u16, found i8
-help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -622,7 +622,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_usize);
    |                ^^^^^^^ expected i16, found usize
-help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -632,7 +632,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u64);
    |                ^^^^^ expected i16, found u64
-help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -642,7 +642,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u32);
    |                ^^^^^ expected i16, found u32
-help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -652,7 +652,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u16);
    |                ^^^^^ expected i16, found u16
-help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u8);
    |                ^^^^ expected i16, found u8
-help: you can convert an `u8` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -672,7 +672,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_isize);
    |                ^^^^^^^ expected i16, found isize
-help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -682,7 +682,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_i64);
    |                ^^^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -692,7 +692,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_i32);
    |                ^^^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -711,7 +711,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_usize);
    |               ^^^^^^^ expected u8, found usize
-help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -721,7 +721,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u64);
    |               ^^^^^ expected u8, found u64
-help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -731,7 +731,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u32);
    |               ^^^^^ expected u8, found u32
-help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -741,7 +741,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u16);
    |               ^^^^^ expected u8, found u16
-help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -751,7 +751,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_isize);
    |               ^^^^^^^ expected u8, found isize
-help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -761,7 +761,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i64);
    |               ^^^^^ expected u8, found i64
-help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -771,7 +771,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i32);
    |               ^^^^^ expected u8, found i32
-help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -781,7 +781,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i16);
    |               ^^^^^ expected u8, found i16
-help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -791,7 +791,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i8);
    |               ^^^^ expected u8, found i8
-help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -801,7 +801,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_usize);
    |               ^^^^^^^ expected i8, found usize
-help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `usize` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -811,7 +811,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u64);
    |               ^^^^^ expected i8, found u64
-help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `u64` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -821,7 +821,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u32);
    |               ^^^^^ expected i8, found u32
-help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `u32` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -831,7 +831,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u16);
    |               ^^^^^ expected i8, found u16
-help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `u16` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -841,7 +841,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u8);
    |               ^^^^ expected i8, found u8
-help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `u8` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -851,7 +851,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_isize);
    |               ^^^^^^^ expected i8, found isize
-help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -861,7 +861,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i64);
    |               ^^^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -871,7 +871,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i32);
    |               ^^^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -881,7 +881,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i16);
    |               ^^^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr
index 596264ba16b42..7eeefa9550543 100644
--- a/src/test/ui/pub/pub-restricted.stderr
+++ b/src/test/ui/pub/pub-restricted.stderr
@@ -21,18 +21,7 @@ LL | pub (b) fn bfn() {}
            `pub(in path::to::module)`: visible only on the specified path
 
 error[E0704]: incorrect visibility restriction
-  --> $DIR/pub-restricted.rs:7:6
-   |
-LL | pub (crate::a) fn cfn() {}
-   |      ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a`
-   |
-   = help: some possible visibility restrictions are:
-           `pub(crate)`: visible only on the current crate
-           `pub(super)`: visible only in the current module's parent
-           `pub(in path::to::module)`: visible only on the specified path
-
-error[E0704]: incorrect visibility restriction
-  --> $DIR/pub-restricted.rs:24:14
+  --> $DIR/pub-restricted.rs:22:14
    |
 LL |         pub (a) invalid: usize,
    |              ^ help: make this visible only to module `a` with `in`: `in a`
@@ -43,7 +32,7 @@ LL |         pub (a) invalid: usize,
            `pub(in path::to::module)`: visible only on the specified path
 
 error[E0704]: incorrect visibility restriction
-  --> $DIR/pub-restricted.rs:33:6
+  --> $DIR/pub-restricted.rs:31:6
    |
 LL | pub (xyz) fn xyz() {}
    |      ^^^ help: make this visible only to module `xyz` with `in`: `in xyz`
@@ -54,11 +43,11 @@ LL | pub (xyz) fn xyz() {}
            `pub(in path::to::module)`: visible only on the specified path
 
 error: visibilities can only be restricted to ancestor modules
-  --> $DIR/pub-restricted.rs:25:17
+  --> $DIR/pub-restricted.rs:23:17
    |
 LL |         pub (in x) non_parent_invalid: usize,
    |                 ^
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0704`.
diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr
index df73ac0b182f0..6772aa1c38d2c 100644
--- a/src/test/ui/repeat_count.stderr
+++ b/src/test/ui/repeat_count.stderr
@@ -42,7 +42,7 @@ error[E0308]: mismatched types
    |
 LL |     let f = [0; -4_isize];
    |                 ^^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     let f = [0; (-4_isize).try_into().unwrap()];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ error[E0308]: mismatched types
    |
 LL |     let f = [0_usize; -1_isize];
    |                       ^^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
    |
 LL |     let f = [0_usize; (-1_isize).try_into().unwrap()];
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr
index 409fabb951adc..97523fe82cd4e 100644
--- a/src/test/ui/shift-various-bad-types.stderr
+++ b/src/test/ui/shift-various-bad-types.stderr
@@ -27,7 +27,7 @@ error[E0308]: mismatched types
    |
 LL |     let _: i32 = 22_i64 >> 1_i32;
    |                  ^^^^^^^^^^^^^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
    |
 LL |     let _: i32 = (22_i64 >> 1_i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr
new file mode 100644
index 0000000000000..6ddd93d632e15
--- /dev/null
+++ b/src/test/ui/symbol-names/basic.stderr
@@ -0,0 +1,14 @@
+error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
+  --> $DIR/basic.rs:3:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(main)
+  --> $DIR/basic.rs:4:1
+   |
+LL | #[rustc_def_path]
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr
new file mode 100644
index 0000000000000..eda8646b5b4de
--- /dev/null
+++ b/src/test/ui/symbol-names/impl1.stderr
@@ -0,0 +1,26 @@
+error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
+  --> $DIR/impl1.rs:8:9
+   |
+LL |         #[rustc_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(foo::Foo::bar)
+  --> $DIR/impl1.rs:9:9
+   |
+LL |         #[rustc_def_path]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E)
+  --> $DIR/impl1.rs:18:9
+   |
+LL |         #[rustc_symbol_name]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(bar::<impl foo::Foo>::baz)
+  --> $DIR/impl1.rs:19:9
+   |
+LL |         #[rustc_def_path]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
index e9c28248044f9..9acd63c2c25f1 100644
--- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
+++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
@@ -6,7 +6,7 @@ LL | fn global_bound_is_hidden() -> u8
 ...
 LL |     B::get_x()
    |     ^^^^^^^^^^ expected u8, found i32
-help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u8` or panic if it the converted value wouldn't fit
    |
 LL |     B::get_x().try_into().unwrap()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr
index f3e1cc41cada2..f51f2defd4759 100644
--- a/src/test/ui/tutorial-suffix-inference-test.stderr
+++ b/src/test/ui/tutorial-suffix-inference-test.stderr
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
    |
 LL |     identity_u16(y);
    |                  ^ expected u16, found i32
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     identity_u16(y.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ error[E0308]: mismatched types
    |
 LL |     identity_u16(a);
    |                  ^ expected u16, found isize
-help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to `u16` or panic if it the converted value wouldn't fit
    |
 LL |     identity_u16(a.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^

From 0f4a5ca33ceb22edd4f2cd12a03806331a2883ed Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 8 May 2019 15:56:39 -0400
Subject: [PATCH 09/24] Added some comments to lowering code.

---
 src/librustc/hir/lowering.rs | 53 ++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 3 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index a49744aa523a9..06f9128cd2263 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1361,26 +1361,73 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    /// Given an associated type constraint like one of these:
+    ///
+    /// ```
+    /// T: Iterator<Item: Debug>
+    ///             ^^^^^^^^^^^
+    /// T: Iterator<Item = Debug>
+    ///             ^^^^^^^^^^^^
+    /// ```
+    ///
+    /// returns a `hir::TypeBinding` representing `Item`.
     fn lower_assoc_ty_constraint(&mut self,
                                  c: &AssocTyConstraint,
                                  itctx: ImplTraitContext<'_>)
                                  -> hir::TypeBinding {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
 
+        // Convert to a type representing the `T::Item` value.
         let ty = match c.kind {
             AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
             AssocTyConstraintKind::Bound { ref bounds } => {
-                let (existential_desugaring, itctx) = match itctx {
+                // Piggy-back on the impl trait context to figure out
+                // the correct behavior.
+                let (desugar_to_impl_trait, itctx) = match itctx {
+                    // We are in the return position:
+                    //
+                    // fn foo() -> impl Iterator<Item: Debug>
+                    //
+                    // so desugar to
+                    //
+                    // fn foo() -> impl Iterator<Item = impl Debug>
                     ImplTraitContext::Existential(_) => (true, itctx),
+
+                    // We are in the argument position, but within a dyn type:
+                    //
+                    // fn foo(x: dyn Iterator<Item: Debug>)
+                    //
+                    // so desugar to
+                    //
+                    // fn foo(x: dyn Iterator<Item = impl Debug>)
                     ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
+
+                    // In `type Foo = dyn Iterator<Item: Debug>` we
+                    // desugar to `type Foo = dyn Iterator<Item = impl
+                    // Debug>` but we have to override the "impl trait
+                    // context" to permit `impl Debug` in this
+                    // position (it desugars then to an existential
+                    // type).
+                    //
                     // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
                     ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
                         (true, ImplTraitContext::Existential(None)),
+
+                    // We are in the argument position, but not within a dyn type:
+                    //
+                    // fn foo(x: impl Iterator<Item: Debug>)
+                    //
+                    // so we leave it as is and this gets expanded in
+                    // astconv to a bound like `<T as Iterator>::Item:
+                    // Debug` where `T` is the type parameter for the
+                    // `impl Iterator`.
                     _ => (false, itctx),
                 };
 
-                if existential_desugaring {
-                    // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`.
+                if desugar_to_impl_trait {
+                    // Desugar `AssocTy: Bounds` into `AssocTy = impl
+                    // Bounds`. We do this by constructing the HIR
+                    // for "impl bounds" and then lowering that.
 
                     let impl_trait_node_id = self.sess.next_node_id();
                     let parent_def_index = self.current_hir_id_owner.last().unwrap().0;

From 538ebd197c52f2551f550d7aa5c82f7b3412c99d Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 8 May 2019 15:58:20 -0400
Subject: [PATCH 10/24] Added some comments, made `add_bounds` private.

---
 src/librustc_typeck/astconv.rs | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e37ad77b086fd..fe17d902c617c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -699,6 +699,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             },
         );
 
+        // Convert associated-type bindings or constraints into a separate vector.
+        // Example: Given this:
+        //
+        //     T: Iterator<Item = u32>
+        //
+        // The `T` is passed in as a self-type; the `Item = u32` is
+        // not a "type parameter" of the `Iterator` trait, but rather
+        // a restriction on `<T as Iterator>::Item`, so it is passed
+        // back separately.
         let assoc_bindings = generic_args.bindings.iter()
             .map(|binding| {
                 let kind = if let hir::TyKind::AssocTyExistential(ref bounds) = binding.ty.node {
@@ -899,7 +908,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         true
     }
 
-    pub fn add_bounds(&self,
+    fn add_bounds(&self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound],
         bounds: &mut Bounds<'tcx>,
@@ -1065,6 +1074,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
 
         match binding.kind {
             ConvertedBindingKind::Equality(ref ty) => {
+                // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
+                // the "projection predicate" for:
+                //
+                // `<T as Iterator>::Item = u32`
                 bounds.projection_bounds.push((candidate.map_bound(|trait_ref| {
                     ty::ProjectionPredicate {
                         projection_ty: ty::ProjectionTy::from_ref_and_name(

From 5bf5994d922744c1d9e44b53a6ad54005fe3489e Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Fri, 10 May 2019 03:46:39 +0100
Subject: [PATCH 11/24] Fixed up some comments.

---
 src/librustc/hir/lowering.rs | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 06f9128cd2263..4c96e106d1f1b 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1381,33 +1381,30 @@ impl<'a> LoweringContext<'a> {
         let ty = match c.kind {
             AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
             AssocTyConstraintKind::Bound { ref bounds } => {
-                // Piggy-back on the impl trait context to figure out
-                // the correct behavior.
+                // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
                     //
-                    // fn foo() -> impl Iterator<Item: Debug>
+                    //     fn foo() -> impl Iterator<Item: Debug>
                     //
                     // so desugar to
                     //
-                    // fn foo() -> impl Iterator<Item = impl Debug>
+                    //     fn foo() -> impl Iterator<Item = impl Debug>
                     ImplTraitContext::Existential(_) => (true, itctx),
 
                     // We are in the argument position, but within a dyn type:
                     //
-                    // fn foo(x: dyn Iterator<Item: Debug>)
+                    //     fn foo(x: dyn Iterator<Item: Debug>)
                     //
                     // so desugar to
                     //
-                    // fn foo(x: dyn Iterator<Item = impl Debug>)
+                    //     fn foo(x: dyn Iterator<Item = impl Debug>)
                     ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
 
-                    // In `type Foo = dyn Iterator<Item: Debug>` we
-                    // desugar to `type Foo = dyn Iterator<Item = impl
-                    // Debug>` but we have to override the "impl trait
-                    // context" to permit `impl Debug` in this
-                    // position (it desugars then to an existential
-                    // type).
+                    // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
+                    // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
+                    // "impl trait context" to permit `impl Debug` in this position (it desugars
+                    // then to an existential type).
                     //
                     // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
                     ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
@@ -1415,19 +1412,17 @@ impl<'a> LoweringContext<'a> {
 
                     // We are in the argument position, but not within a dyn type:
                     //
-                    // fn foo(x: impl Iterator<Item: Debug>)
+                    //     fn foo(x: impl Iterator<Item: Debug>)
                     //
-                    // so we leave it as is and this gets expanded in
-                    // astconv to a bound like `<T as Iterator>::Item:
-                    // Debug` where `T` is the type parameter for the
+                    // so we leave it as is and this gets expanded in astconv to a bound like
+                    // `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
                     // `impl Iterator`.
                     _ => (false, itctx),
                 };
 
                 if desugar_to_impl_trait {
-                    // Desugar `AssocTy: Bounds` into `AssocTy = impl
-                    // Bounds`. We do this by constructing the HIR
-                    // for "impl bounds" and then lowering that.
+                    // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
+                    // constructing the HIR for "impl bounds" and then lowering that.
 
                     let impl_trait_node_id = self.sess.next_node_id();
                     let parent_def_index = self.current_hir_id_owner.last().unwrap().0;

From f472cd9c02e77654ba6ba324c0b4b15aefa96f48 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 8 May 2019 15:57:06 -0400
Subject: [PATCH 12/24] Addressed points raised in review.

---
 src/librustc/hir/intravisit.rs          | 12 +++--
 src/librustc/hir/lowering.rs            | 52 +++++++++++++---------
 src/librustc/hir/mod.rs                 | 53 +++++++++++++++++-----
 src/librustc/hir/print.rs               | 16 ++++---
 src/librustc/middle/resolve_lifetime.rs |  6 +--
 src/librustc_typeck/astconv.rs          | 13 +++---
 src/librustdoc/clean/auto_trait.rs      |  4 +-
 src/librustdoc/clean/mod.rs             | 58 ++++++++++++++++++++-----
 src/librustdoc/clean/simplify.rs        |  4 +-
 src/librustdoc/html/format.rs           | 23 ++++++++--
 10 files changed, 172 insertions(+), 69 deletions(-)

diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index da4d41c9d872f..1c66f8bdf81bd 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -626,9 +626,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyKind::CVarArgs(ref lt) => {
             visitor.visit_lifetime(lt)
         }
-        TyKind::AssocTyExistential(ref bounds) => {
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
         TyKind::Infer | TyKind::Err => {}
     }
 }
@@ -677,7 +674,14 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
                                                    type_binding: &'v TypeBinding) {
     visitor.visit_id(type_binding.hir_id);
     visitor.visit_ident(type_binding.ident);
-    visitor.visit_ty(&type_binding.ty);
+    match type_binding.kind {
+        TypeBindingKind::Equality { ref ty } => {
+            visitor.visit_ty(ty);
+        }
+        TypeBindingKind::Constraint { ref bounds } => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
 }
 
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 4c96e106d1f1b..1bfff138d8dca 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1377,9 +1377,10 @@ impl<'a> LoweringContext<'a> {
                                  -> hir::TypeBinding {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
 
-        // Convert to a type representing the `T::Item` value.
-        let ty = match c.kind {
-            AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx),
+        let kind = match c.kind {
+            AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality {
+                ty: self.lower_ty(ty, itctx)
+            },
             AssocTyConstraintKind::Bound { ref bounds } => {
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
@@ -1422,7 +1423,7 @@ impl<'a> LoweringContext<'a> {
 
                 if desugar_to_impl_trait {
                     // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
-                    // constructing the HIR for "impl bounds" and then lowering that.
+                    // constructing the HIR for `impl bounds...` and then lowering that.
 
                     let impl_trait_node_id = self.sess.next_node_id();
                     let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
@@ -1436,27 +1437,27 @@ impl<'a> LoweringContext<'a> {
                     );
 
                     self.with_dyn_type_scope(false, |this| {
-                        this.lower_ty(
+                        let ty = this.lower_ty(
                             &Ty {
                                 id: this.sess.next_node_id(),
                                 node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
                                 span: DUMMY_SP,
                             },
                             itctx,
-                        )
+                        );
+
+                        hir::TypeBindingKind::Equality {
+                            ty
+                        }
                     })
                 } else {
-                    // Desugar `AssocTy: Bounds` into `AssocTy = ∃ T (T: Bounds)`, where the
-                    // "false existential" later desugars into a trait predicate.
-
+                    // Desugar `AssocTy: Bounds` into a type binding where the
+                    // later desugars into a trait predicate.
                     let bounds = self.lower_param_bounds(bounds, itctx);
 
-                    let id = self.sess.next_node_id();
-                    P(hir::Ty {
-                        hir_id: self.lower_node_id(id),
-                        node: hir::TyKind::AssocTyExistential(bounds),
-                        span: DUMMY_SP,
-                    })
+                    hir::TypeBindingKind::Constraint {
+                        bounds
+                    }
                 }
             }
         };
@@ -1464,7 +1465,7 @@ impl<'a> LoweringContext<'a> {
         hir::TypeBinding {
             hir_id: self.lower_node_id(c.id),
             ident: c.ident,
-            ty,
+            kind,
             span: c.span,
         }
     }
@@ -2359,10 +2360,17 @@ impl<'a> LoweringContext<'a> {
                             hir::TypeBinding {
                                 hir_id: this.next_id(),
                                 ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
-                                ty: output
-                                    .as_ref()
-                                    .map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed()))
-                                    .unwrap_or_else(|| P(mk_tup(this, hir::HirVec::new(), span))),
+                                kind: hir::TypeBindingKind::Equality {
+                                    ty: output
+                                        .as_ref()
+                                        .map(|ty| this.lower_ty(
+                                            &ty,
+                                            ImplTraitContext::disallowed()
+                                        ))
+                                        .unwrap_or_else(||
+                                            P(mk_tup(this, hir::HirVec::new(), span))
+                                        ),
+                                },
                                 span: output.as_ref().map_or(span, |ty| ty.span),
                             }
                         ],
@@ -2666,7 +2674,9 @@ impl<'a> LoweringContext<'a> {
             args: hir_vec![],
             bindings: hir_vec![hir::TypeBinding {
                 ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
-                ty: output_ty,
+                kind: hir::TypeBindingKind::Equality {
+                    ty: output_ty,
+                },
                 hir_id: self.next_id(),
                 span,
             }],
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f884651e8be32..2aaf5ec775d49 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1780,7 +1780,7 @@ pub struct ImplItem {
     pub span: Span,
 }
 
-/// Represents different contents within `impl`s.
+/// Represents various kinds of content within an `impl`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum ImplItemKind {
     /// An associated constant of the given type, set to the constant result
@@ -1794,16 +1794,51 @@ pub enum ImplItemKind {
     Existential(GenericBounds),
 }
 
-// Bind a type to an associated type (`A = Foo`).
+/// Bind a type to an associated type (i.e., `A = Foo`).
+///
+/// Bindings like `A: Debug` are represented as a special type `A =
+/// $::Debug` that is understood by the astconv code.
+///
+/// FIXME(alexreg) -- why have a separate type for the binding case,
+/// wouldn't it be better to make the `ty` field an enum like:
+///
+/// ```
+/// enum TypeBindingKind {
+///    Equals(...),
+///    Binding(...),
+/// }
+/// ```
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct TypeBinding {
     pub hir_id: HirId,
     #[stable_hasher(project(name))]
     pub ident: Ident,
-    pub ty: P<Ty>,
+    pub kind: TypeBindingKind,
     pub span: Span,
 }
 
+// Represents the two kinds of type bindings.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum TypeBindingKind {
+    /// E.g., `Foo<Bar: Send>`.
+    Constraint {
+        bounds: HirVec<GenericBound>,
+    },
+    /// E.g., `Foo<Bar = ()>`.
+    Equality {
+        ty: P<Ty>,
+    },
+}
+
+impl TypeBinding {
+    pub fn ty(&self) -> &Ty {
+        match self.kind {
+            TypeBindingKind::Equality { ref ty } => ty,
+            _ => bug!("expected equality type binding for parenthesized generic args"),
+        }
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Ty {
     pub hir_id: HirId,
@@ -1898,8 +1933,6 @@ pub enum TyKind {
     /// Placeholder for C-variadic arguments. We "spoof" the `VaList` created
     /// from the variadic arguments. This type is only valid up to typeck.
     CVarArgs(Lifetime),
-    /// The existential type (i.e., `impl Trait`) that constrains an associated type.
-    AssocTyExistential(HirVec<GenericBound>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
@@ -2236,18 +2269,18 @@ impl StructField {
     }
 }
 
-/// Fields and constructor ids of enum variants and structs
+/// Fields and constructor IDs of enum variants and structs.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum VariantData {
-    /// Struct variant.
+    /// A struct variant.
     ///
-    /// e.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
+    /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
     Struct(HirVec<StructField>, /* recovered */ bool),
-    /// Tuple variant.
+    /// A tuple variant.
     ///
     /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
     Tuple(HirVec<StructField>, HirId),
-    /// Unit variant.
+    /// A unit variant.
     ///
     /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`.
     Unit(HirId),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index c8f9e4c7043e0..c8615f0ed1b93 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -409,9 +409,6 @@ impl<'a> State<'a> {
             hir::TyKind::CVarArgs(_) => {
                 self.s.word("...")?;
             }
-            hir::TyKind::AssocTyExistential(ref bounds) => {
-                self.print_bounds(":", bounds)?;
-            }
         }
         self.end()
     }
@@ -1648,7 +1645,7 @@ impl<'a> State<'a> {
 
             self.space_if_not_bol()?;
             self.word_space("->")?;
-            self.print_type(&generic_args.bindings[0].ty)?;
+            self.print_type(generic_args.bindings[0].ty())?;
         } else {
             let start = if colons_before_params { "::<" } else { "<" };
             let empty = Cell::new(true);
@@ -1693,8 +1690,15 @@ impl<'a> State<'a> {
                 start_or_comma(self)?;
                 self.print_ident(binding.ident)?;
                 self.s.space()?;
-                self.word_space("=")?;
-                self.print_type(&binding.ty)?;
+                match generic_args.bindings[0].kind {
+                    hir::TypeBindingKind::Equality { ref ty } => {
+                        self.word_space("=")?;
+                        self.print_type(ty)?;
+                    }
+                    hir::TypeBindingKind::Constraint { ref bounds } => {
+                        self.print_bounds(":", bounds)?;
+                    }
+                }
             }
 
             if !empty.get() {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 2e56ca6f56352..331b74db080bf 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) {
         let output = match fd.output {
             hir::DefaultReturn(_) => None,
-            hir::Return(ref ty) => Some(ty),
+            hir::Return(ref ty) => Some(&**ty),
         };
         self.visit_fn_like_elision(&fd.inputs, output);
     }
@@ -1884,7 +1884,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         if generic_args.parenthesized {
             let was_in_fn_syntax = self.is_in_fn_syntax;
             self.is_in_fn_syntax = true;
-            self.visit_fn_like_elision(generic_args.inputs(), Some(&generic_args.bindings[0].ty));
+            self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
             self.is_in_fn_syntax = was_in_fn_syntax;
             return;
         }
@@ -2020,7 +2020,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx P<hir::Ty>>) {
+    fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx hir::Ty>) {
         debug!("visit_fn_like_elision: enter");
         let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
         let arg_scope = Scope::Elision {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fe17d902c617c..4a2949fa6b069 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -710,10 +710,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         // back separately.
         let assoc_bindings = generic_args.bindings.iter()
             .map(|binding| {
-                let kind = if let hir::TyKind::AssocTyExistential(ref bounds) = binding.ty.node {
-                    ConvertedBindingKind::Constraint(bounds.clone())
-                } else {
-                    ConvertedBindingKind::Equality(self.ast_ty_to_ty(&binding.ty))
+                let kind = match binding.kind {
+                    hir::TypeBindingKind::Equality { ref ty } =>
+                        ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)),
+                    hir::TypeBindingKind::Constraint { ref bounds } =>
+                        ConvertedBindingKind::Constraint(bounds.clone()),
                 };
                 ConvertedBinding {
                     item_name: binding.ident,
@@ -2060,10 +2061,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 let region = self.ast_region_to_region(&lt, None);
                 tcx.type_of(va_list_did).subst(tcx, &[region.into()])
             }
-            hir::TyKind::AssocTyExistential(..) => {
-                // Type is never actually used.
-                tcx.types.err
-            }
             hir::TyKind::Err => {
                 tcx.types.err
             }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 8e2460a14b87a..60d6c33f81afc 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -626,7 +626,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                                             } => {
                                                 bindings.push(TypeBinding {
                                                     name: left_name.clone(),
-                                                    ty: rhs,
+                                                    kind: TypeBindingKind::Equality {
+                                                        ty: rhs,
+                                                    },
                                                 });
                                             }
                                             &mut GenericArgs::Parenthesized { .. } => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index af283e6c0bc6f..03d16feb483a9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1979,7 +1979,7 @@ impl FnDecl {
                 match &bounds[0] {
                     GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
                         let bindings = trait_.bindings().unwrap();
-                        FunctionRetTy::Return(bindings[0].ty.clone())
+                        FunctionRetTy::Return(bindings[0].ty().clone())
                     }
                     _ => panic!("unexpected desugaring of async function"),
                 }
@@ -2937,11 +2937,8 @@ impl Clean<Type> for hir::Ty {
             }
             TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
             TyKind::Infer | TyKind::Err => Infer,
-            TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
+            TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.node),
             TyKind::CVarArgs(_) => CVarArgs,
-            TyKind::AssocTyExistential(ref bounds) => {
-                ImplTrait(bounds.into_iter().map(|b| b.clean(cx)).collect())
-            }
         }
     }
 }
@@ -3057,7 +3054,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
-                        ty: pb.skip_binder().ty.clean(cx)
+                        kind: TypeBindingKind::Equality {
+                            ty: pb.skip_binder().ty.clean(cx)
+                        },
                     });
                 }
 
@@ -3113,7 +3112,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                                 Some(TypeBinding {
                                     name: cx.tcx.associated_item(proj.projection_ty.item_def_id)
                                                 .ident.name.clean(cx),
-                                    ty: proj.ty.clean(cx),
+                                    kind: TypeBindingKind::Equality {
+                                        ty: proj.ty.clean(cx),
+                                    },
                                 })
                             } else {
                                 None
@@ -3498,7 +3499,7 @@ pub enum GenericArgs {
 impl Clean<GenericArgs> for hir::GenericArgs {
     fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
         if self.parenthesized {
-            let output = self.bindings[0].ty.clean(cx);
+            let output = self.bindings[0].ty().clean(cx);
             GenericArgs::Parenthesized {
                 inputs: self.inputs().clean(cx),
                 output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
@@ -4346,18 +4347,53 @@ impl Clean<Deprecation> for attr::Deprecation {
     }
 }
 
-/// An equality constraint on an associated type, e.g., `A = Bar` in `Foo<A = Bar>`
+/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
 #[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
 pub struct TypeBinding {
     pub name: String,
-    pub ty: Type
+    pub kind: TypeBindingKind,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
+pub enum TypeBindingKind {
+    Equality {
+        ty: Type,
+    },
+    Constraint {
+        bounds: Vec<GenericBound>,
+    },
+}
+
+impl TypeBinding {
+    pub fn ty(&self) -> &Type {
+        match self.kind {
+            TypeBindingKind::Equality { ref ty } => ty,
+            _ => panic!("expected equality type binding for parenthesized generic args"),
+        }
+    }
 }
 
 impl Clean<TypeBinding> for hir::TypeBinding {
     fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
         TypeBinding {
             name: self.ident.name.clean(cx),
-            ty: self.ty.clean(cx)
+            kind: self.kind.clean(cx),
+        }
+    }
+}
+
+impl Clean<TypeBindingKind> for hir::TypeBindingKind {
+    fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind {
+        match *self {
+            hir::TypeBindingKind::Equality { ref ty } =>
+                TypeBindingKind::Equality {
+                    ty: ty.clean(cx),
+                },
+            hir::TypeBindingKind::Constraint { ref bounds } =>
+                TypeBindingKind::Constraint {
+                    bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(),
+                },
         }
     }
 }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 8ca570cb443c9..36e6a6003df09 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -91,7 +91,9 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
                 PP::AngleBracketed { ref mut bindings, .. } => {
                     bindings.push(clean::TypeBinding {
                         name: name.clone(),
-                        ty: rhs.clone(),
+                        kind: clean::TypeBindingKind::Equality {
+                            ty: rhs.clone(),
+                        },
                     });
                 }
                 PP::Parenthesized { ref mut output, .. } => {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 38cde12100056..fa3bc3f5f4f8b 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1019,11 +1019,26 @@ impl fmt::Display for clean::ImportSource {
 
 impl fmt::Display for clean::TypeBinding {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            write!(f, "{} = {:#}", self.name, self.ty)
-        } else {
-            write!(f, "{} = {}", self.name, self.ty)
+        f.write_str(&self.name)?;
+        match self.kind {
+            clean::TypeBindingKind::Equality { ref ty } => {
+                if f.alternate() {
+                    write!(f, " = {:#}", ty)?;
+                } else {
+                    write!(f, " = {}", ty)?;
+                }
+            }
+            clean::TypeBindingKind::Constraint { ref bounds } => {
+                if !bounds.is_empty() {
+                    if f.alternate() {
+                        write!(f, ": {:#}", GenericBounds(bounds))?;
+                    } else {
+                        write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
+                    }
+                }
+            }
         }
+        Ok(())
     }
 }
 

From c105c28de0df081c29a789fb58250eebc48b5eed Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Mon, 20 May 2019 00:22:44 +0100
Subject: [PATCH 13/24] Fixed rebase fallout.

---
 src/librustc/hir/lowering.rs | 1 -
 src/libsyntax_pos/symbol.rs  | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 1bfff138d8dca..d6ad335525c14 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1431,7 +1431,6 @@ impl<'a> LoweringContext<'a> {
                         parent_def_index,
                         impl_trait_node_id,
                         DefPathData::ImplTrait,
-                        DefIndexAddressSpace::High,
                         Mark::root(),
                         DUMMY_SP
                     );
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 8847e94127be6..4e080d115d2a8 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -141,6 +141,7 @@ symbols! {
         arm_target_feature,
         asm,
         associated_consts,
+        associated_type_bounds,
         associated_type_defaults,
         associated_types,
         async_await,

From 10b6daa6c8e1e4b2a041c3a28cae8e1c139c1bd2 Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Mon, 20 May 2019 01:08:52 +0100
Subject: [PATCH 14/24] Reblessed tests.

---
 .../libtest-json/output.json                  |   2 +-
 src/test/run-pass/multi-panic.rs              |   2 +-
 .../rustdoc-ui/failed-doctest-output.stdout   |   2 +-
 .../associated-type-bounds/duplicate.stderr   |   7 +-
 .../associated-type-bounds/dyn-lcsit.stderr   |   6 +
 .../implied-region-constraints.stderr         |   9 +-
 .../ui/associated-type-bounds/lcsit.stderr    |   6 +
 .../associated-types-path-2.stderr            |   2 +-
 .../borrowck/borrowck-closures-two-mut.stderr | 104 ++----------
 src/test/ui/borrowck/borrowck-reinit.stderr   |  16 +-
 .../ui/borrowck/borrowck-storage-dead.stderr  |  12 +-
 src/test/ui/borrowck/immutable-arg.stderr     |  14 +-
 src/test/ui/borrowck/issue-41962.stderr       |  24 +--
 .../const-param-before-other-params.stderr    |  12 +-
 .../deprecation-in-staged-api.stderr          |   2 +-
 .../yield-while-local-borrowed.stderr         |  32 +---
 src/test/ui/indexing-requires-a-uint.stderr   |   2 +-
 .../integer-literal-suffix-inference.stderr   |  36 ++--
 src/test/ui/issues/issue-13359.stderr         |   4 +-
 src/test/ui/issues/issue-31910.stderr         |   2 +-
 src/test/ui/issues/issue-45697-1.stderr       |  14 +-
 src/test/ui/issues/issue-45697.stderr         |  14 +-
 src/test/ui/issues/issue-46471-1.stderr       |  17 +-
 src/test/ui/issues/issue-46471.stderr         |  20 +--
 src/test/ui/issues/issue-46472.stderr         |  24 +--
 .../liveness-assign-imm-local-notes.stderr    |  51 ++----
 ...od-ambig-one-trait-unknown-int-type.stderr |   2 +-
 .../ui/mismatched_types/issue-26480.stderr    |   2 +-
 .../ui/moves/moves-based-on-type-tuple.stderr |  16 +-
 src/test/ui/nll/get_default.stderr            |  58 ++-----
 .../ui/nll/loan_ends_mid_block_pair.stderr    |  60 +------
 .../ui/nll/loan_ends_mid_block_vec.stderr     |  88 +---------
 .../nll/region-ends-after-if-condition.stderr |  32 +---
 src/test/ui/nll/return_from_loop.stderr       |  32 +---
 src/test/ui/numeric/const-scope.stderr        |   2 +-
 src/test/ui/numeric/len.stderr                |   2 +-
 src/test/ui/numeric/numeric-cast-2.stderr     |   6 +-
 src/test/ui/numeric/numeric-cast.stderr       | 156 +++++++++---------
 src/test/ui/pattern/const-pat-ice.stderr      |   2 +-
 src/test/ui/pub/pub-restricted.stderr         |  19 ++-
 src/test/ui/repeat_count.stderr               |   4 +-
 src/test/ui/shift-various-bad-types.stderr    |   2 +-
 src/test/ui/symbol-names/basic.stderr         |   2 +-
 src/test/ui/symbol-names/impl1.stderr         |   4 +-
 ...ounds-inconsistent-projection-error.stderr |   2 +-
 .../ui/tutorial-suffix-inference-test.stderr  |   4 +-
 46 files changed, 255 insertions(+), 676 deletions(-)
 create mode 100644 src/test/ui/associated-type-bounds/dyn-lcsit.stderr
 create mode 100644 src/test/ui/associated-type-bounds/lcsit.stderr

diff --git a/src/test/run-make-fulldeps/libtest-json/output.json b/src/test/run-make-fulldeps/libtest-json/output.json
index c8b3d08186929..0caf268aa007f 100644
--- a/src/test/run-make-fulldeps/libtest-json/output.json
+++ b/src/test/run-make-fulldeps/libtest-json/output.json
@@ -2,7 +2,7 @@
 { "type": "test", "event": "started", "name": "a" }
 { "type": "test", "name": "a", "event": "ok" }
 { "type": "test", "event": "started", "name": "b" }
-{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
 { "type": "test", "event": "started", "name": "c" }
 { "type": "test", "name": "c", "event": "ok" }
 { "type": "test", "event": "started", "name": "d" }
diff --git a/src/test/run-pass/multi-panic.rs b/src/test/run-pass/multi-panic.rs
index 900b2b2206f48..8bc0002065271 100644
--- a/src/test/run-pass/multi-panic.rs
+++ b/src/test/run-pass/multi-panic.rs
@@ -8,7 +8,7 @@ fn check_for_no_backtrace(test: std::process::Output) {
     let mut it = err.lines();
 
     assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked at")), Some(true));
-    assert_eq!(it.next(), Some("note: Run with `RUST_BACKTRACE=1` \
+    assert_eq!(it.next(), Some("note: run with `RUST_BACKTRACE=1` \
                                 environment variable to display a backtrace."));
     assert_eq!(it.next().map(|l| l.starts_with("thread 'main' panicked at")), Some(true));
     assert_eq!(it.next(), None);
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index 0c42c652d786c..e362ecf349e45 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -27,7 +27,7 @@ stderr:
 stderr 1
 stderr 2
 thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1
-note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 
 
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
index fbf02ddc7032f..68367c916546c 100644
--- a/src/test/ui/associated-type-bounds/duplicate.stderr
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -1,3 +1,9 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/duplicate.rs:7:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
   --> $DIR/duplicate.rs:12:36
    |
@@ -624,4 +630,3 @@ error: could not find defining uses
 
 error: aborting due to 93 previous errors
 
-For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/associated-type-bounds/dyn-lcsit.stderr b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr
new file mode 100644
index 0000000000000..5fe4818ef8fed
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/dyn-lcsit.stderr
@@ -0,0 +1,6 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/dyn-lcsit.rs:4:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
index b07b20272a8c0..9968f3e8bac5e 100644
--- a/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.stderr
@@ -2,9 +2,7 @@ error[E0623]: lifetime mismatch
   --> $DIR/implied-region-constraints.rs:19:64
    |
 LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
-   |                          -------------
-   |                          |
-   |                          this type is declared with multiple lifetimes...
+   |                          ------------- this type is declared with multiple lifetimes...
 ...
 LL |     let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
    |                                                                ^^^^^ ...but data with one lifetime flows into the other here
@@ -13,13 +11,10 @@ error[E0623]: lifetime mismatch
   --> $DIR/implied-region-constraints.rs:40:72
    |
 LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
-   |                           --------------
-   |                           |
-   |                           this type is declared with multiple lifetimes...
+   |                           -------------- this type is declared with multiple lifetimes...
 ...
 LL |             let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
    |                                                                        ^^ ...but data with one lifetime flows into the other here
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/associated-type-bounds/lcsit.stderr b/src/test/ui/associated-type-bounds/lcsit.stderr
new file mode 100644
index 0000000000000..8fda11beddc4f
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/lcsit.stderr
@@ -0,0 +1,6 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/lcsit.rs:4:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr
index c25f12d008703..1405cb1b4736c 100644
--- a/src/test/ui/associated-types/associated-types-path-2.stderr
+++ b/src/test/ui/associated-types/associated-types-path-2.stderr
@@ -49,7 +49,7 @@ error[E0308]: mismatched types
    |
 LL |     let _: i32 = f2(2i32);
    |                  ^^^^^^^^ expected i32, found u32
-help: you can convert an `u32` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     let _: i32 = f2(2i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
index e881201ddfcc0..bffb11640744c 100644
--- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr
@@ -1,80 +1,5 @@
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
-  --> $DIR/borrowck-closures-two-mut.rs:14:24
-   |
-LL |     let c1 = to_fn_mut(|| x = 4);
-   |                        -- - previous borrow occurs due to use of `x` in closure
-   |                        |
-   |                        first mutable borrow occurs here
-LL |     let c2 = to_fn_mut(|| x = 5);
-   |                        ^^ - borrow occurs due to use of `x` in closure
-   |                        |
-   |                        second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
-  --> $DIR/borrowck-closures-two-mut.rs:26:24
-   |
-LL |     let c1 = to_fn_mut(|| set(&mut x));
-   |                        --          - previous borrow occurs due to use of `x` in closure
-   |                        |
-   |                        first mutable borrow occurs here
-LL |     let c2 = to_fn_mut(|| set(&mut x));
-   |                        ^^          - borrow occurs due to use of `x` in closure
-   |                        |
-   |                        second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
-  --> $DIR/borrowck-closures-two-mut.rs:34:24
-   |
-LL |     let c1 = to_fn_mut(|| x = 5);
-   |                        -- - previous borrow occurs due to use of `x` in closure
-   |                        |
-   |                        first mutable borrow occurs here
-LL |     let c2 = to_fn_mut(|| set(&mut x));
-   |                        ^^          - borrow occurs due to use of `x` in closure
-   |                        |
-   |                        second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
-  --> $DIR/borrowck-closures-two-mut.rs:42:24
-   |
-LL |     let c1 = to_fn_mut(|| x = 5);
-   |                        -- - previous borrow occurs due to use of `x` in closure
-   |                        |
-   |                        first mutable borrow occurs here
-LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
-   |                        ^^                                  - borrow occurs due to use of `x` in closure
-   |                        |
-   |                        second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
-  --> $DIR/borrowck-closures-two-mut.rs:55:24
-   |
-LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
-   |                        --           - previous borrow occurs due to use of `x` in closure
-   |                        |
-   |                        first mutable borrow occurs here
-LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
-   |                        ^^           - borrow occurs due to use of `x` in closure
-   |                        |
-   |                        second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
-  --> $DIR/borrowck-closures-two-mut.rs:14:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:12:24
    |
 LL |     let c1 = to_fn_mut(|| x = 4);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -84,12 +9,11 @@ LL |     let c2 = to_fn_mut(|| x = 5);
    |                        ^^ - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
-  --> $DIR/borrowck-closures-two-mut.rs:26:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:23:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut x));
    |                        --          - first borrow occurs due to use of `x` in closure
@@ -99,12 +23,11 @@ LL |     let c2 = to_fn_mut(|| set(&mut x));
    |                        ^^          - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
-  --> $DIR/borrowck-closures-two-mut.rs:34:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:30:24
    |
 LL |     let c1 = to_fn_mut(|| x = 5);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -114,12 +37,11 @@ LL |     let c2 = to_fn_mut(|| set(&mut x));
    |                        ^^          - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
-  --> $DIR/borrowck-closures-two-mut.rs:42:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:37:24
    |
 LL |     let c1 = to_fn_mut(|| x = 5);
    |                        -- - first borrow occurs due to use of `x` in closure
@@ -129,12 +51,12 @@ LL |     let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nes
    |                        ^^                                  - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-...
+LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
-  --> $DIR/borrowck-closures-two-mut.rs:55:24
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-closures-two-mut.rs:49:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
    |                        --           - first borrow occurs due to use of `x` in closure
@@ -144,10 +66,10 @@ LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
    |                        ^^           - second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
-...
+LL |
 LL |     drop((c1, c2));
    |           -- first borrow later used here
 
-error: aborting due to 10 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr
index 3618a7cb2cd39..f8f14b6435f08 100644
--- a/src/test/ui/borrowck/borrowck-reinit.stderr
+++ b/src/test/ui/borrowck/borrowck-reinit.stderr
@@ -1,15 +1,5 @@
-error[E0382]: use of moved value: `x` (Ast)
-  --> $DIR/borrowck-reinit.rs:8:16
-   |
-LL |     drop(x);
-   |          - value moved here
-LL |     let _ = (1,x);
-   |                ^ value used here after move
-   |
-   = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `x` (Mir)
-  --> $DIR/borrowck-reinit.rs:8:16
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-reinit.rs:6:16
    |
 LL |     let mut x = Box::new(0);
    |         ----- move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
@@ -19,6 +9,6 @@ LL |     drop(x);
 LL |     let _ = (1,x);
    |                ^ value used here after move
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr
index c291ed224eb3c..5b9f49c2e7c92 100644
--- a/src/test/ui/borrowck/borrowck-storage-dead.stderr
+++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr
@@ -1,15 +1,9 @@
-error[E0381]: use of possibly uninitialized variable: `x` (Ast)
-  --> $DIR/borrowck-storage-dead.rs:18:17
+error[E0381]: use of possibly uninitialized variable: `x`
+  --> $DIR/borrowck-storage-dead.rs:16:17
    |
 LL |         let _ = x + 1;
    |                 ^ use of possibly uninitialized `x`
 
-error[E0381]: use of possibly uninitialized variable: `x` (Mir)
-  --> $DIR/borrowck-storage-dead.rs:18:17
-   |
-LL |         let _ = x + 1;
-   |                 ^ use of possibly uninitialized `x`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/immutable-arg.stderr b/src/test/ui/borrowck/immutable-arg.stderr
index 8b21e92666674..7255ca327e753 100644
--- a/src/test/ui/borrowck/immutable-arg.stderr
+++ b/src/test/ui/borrowck/immutable-arg.stderr
@@ -1,19 +1,11 @@
-error[E0384]: cannot assign twice to immutable variable `_x` (Ast)
-  --> $DIR/immutable-arg.rs:4:5
-   |
-LL | fn foo(_x: u32) {
-   |        -- first assignment to `_x`
-LL |     _x = 4;
-   |     ^^^^^^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign to immutable argument `_x` (Mir)
-  --> $DIR/immutable-arg.rs:4:5
+error[E0384]: cannot assign to immutable argument `_x`
+  --> $DIR/immutable-arg.rs:2:5
    |
 LL | fn foo(_x: u32) {
    |        -- help: make this binding mutable: `mut _x`
 LL |     _x = 4;
    |     ^^^^^^ cannot assign to immutable argument
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr
index fd4d318b5ddf1..422d1605aa46b 100644
--- a/src/test/ui/borrowck/issue-41962.stderr
+++ b/src/test/ui/borrowck/issue-41962.stderr
@@ -1,29 +1,11 @@
-error[E0382]: use of partially moved value: `maybe` (Ast)
-  --> $DIR/issue-41962.rs:7:30
-   |
-LL |         if let Some(thing) = maybe {
-   |                     -----    ^^^^^ value used here after move
-   |                     |
-   |                     value moved here
-   |
-   = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast)
-  --> $DIR/issue-41962.rs:7:21
-   |
-LL |         if let Some(thing) = maybe {
-   |                     ^^^^^ value moved here in previous iteration of loop
-   |
-   = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value (Mir)
-  --> $DIR/issue-41962.rs:7:21
+error[E0382]: use of moved value
+  --> $DIR/issue-41962.rs:5:21
    |
 LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 78f129e79ea24..33f981d1eba9b 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -4,17 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error: type parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:4:21
    |
-LL | fn foo<const X: (), T>(_: &T) {
-   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
+LL | fn bar<const X: (), 'a>(_: &'a ()) {
+   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
 
-error: lifetime parameters must be declared prior to const parameters
+error: type parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:8:21
    |
-LL | fn bar<const X: (), 'a>(_: &'a ()) {
-   |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
+LL | fn foo<const X: (), T>(_: &T) {
+   |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.stderr b/src/test/ui/deprecation/deprecation-in-staged-api.stderr
index 6a8056ec2d9d6..c6881d5a5735f 100644
--- a/src/test/ui/deprecation/deprecation-in-staged-api.stderr
+++ b/src/test/ui/deprecation/deprecation-in-staged-api.stderr
@@ -1,4 +1,4 @@
-error: `#[deprecated]` cannot be used in staged api, use `#[rustc_deprecated]` instead
+error: `#[deprecated]` cannot be used in staged API; use `#[rustc_deprecated]` instead
   --> $DIR/deprecation-in-staged-api.rs:8:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr
index 56f425b7e70a0..c1513ef9b7157 100644
--- a/src/test/ui/generator/yield-while-local-borrowed.stderr
+++ b/src/test/ui/generator/yield-while-local-borrowed.stderr
@@ -1,39 +1,21 @@
-error[E0626]: borrow may still be in use when generator yields (Ast)
-  --> $DIR/yield-while-local-borrowed.rs:15:22
-   |
-LL |         let a = &mut 3;
-   |                      ^
-...
-LL |         yield();
-   |         ------- possible yield occurs here
-
-error[E0626]: borrow may still be in use when generator yields (Ast)
-  --> $DIR/yield-while-local-borrowed.rs:43:22
-   |
-LL |             let b = &a;
-   |                      ^
-...
-LL |             yield();
-   |             ------- possible yield occurs here
-
-error[E0626]: borrow may still be in use when generator yields (Mir)
-  --> $DIR/yield-while-local-borrowed.rs:15:17
+error[E0626]: borrow may still be in use when generator yields
+  --> $DIR/yield-while-local-borrowed.rs:13:17
    |
 LL |         let a = &mut 3;
    |                 ^^^^^^
-...
+LL |
 LL |         yield();
    |         ------- possible yield occurs here
 
-error[E0626]: borrow may still be in use when generator yields (Mir)
-  --> $DIR/yield-while-local-borrowed.rs:43:21
+error[E0626]: borrow may still be in use when generator yields
+  --> $DIR/yield-while-local-borrowed.rs:40:21
    |
 LL |             let b = &a;
    |                     ^^
-...
+LL |
 LL |             yield();
    |             ------- possible yield occurs here
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr
index 9dafe1c24f1c2..3300db58d44c3 100644
--- a/src/test/ui/indexing-requires-a-uint.stderr
+++ b/src/test/ui/indexing-requires-a-uint.stderr
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
    |
 LL |     bar::<isize>(i);  // i should not be re-coerced back to an isize
    |                  ^ expected isize, found usize
-help: you can convert an `usize` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     bar::<isize>(i.try_into().unwrap());  // i should not be re-coerced back to an isize
    |                  ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr
index b5b3f27f0e6cd..80b601dc4394b 100644
--- a/src/test/ui/integer-literal-suffix-inference.stderr
+++ b/src/test/ui/integer-literal-suffix-inference.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a16);
    |           ^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(a16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a32);
    |           ^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(a32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(a64);
    |           ^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(a64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(a32);
    |            ^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     id_i16(a32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(a64);
    |            ^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     id_i16(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i32(a64);
    |            ^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     id_i32(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c16);
    |           ^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(c16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,7 +127,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c32);
    |           ^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(c32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -137,7 +137,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i8(c64);
    |           ^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     id_i8(c64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(c32);
    |            ^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     id_i16(c32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i16(c64);
    |            ^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     id_i16(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -194,7 +194,7 @@ error[E0308]: mismatched types
    |
 LL |     id_i32(c64);
    |            ^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     id_i32(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -231,7 +231,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b16);
    |           ^^^ expected u8, found u16
-help: you can convert an `u16` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     id_u8(b16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b32);
    |           ^^^ expected u8, found u32
-help: you can convert an `u32` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     id_u8(b32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -251,7 +251,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u8(b64);
    |           ^^^ expected u8, found u64
-help: you can convert an `u64` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     id_u8(b64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u16(b32);
    |            ^^^ expected u16, found u32
-help: you can convert an `u32` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     id_u16(b32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u16(b64);
    |            ^^^ expected u16, found u64
-help: you can convert an `u64` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     id_u16(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -308,7 +308,7 @@ error[E0308]: mismatched types
    |
 LL |     id_u32(b64);
    |            ^^^ expected u32, found u64
-help: you can convert an `u64` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     id_u32(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr
index b16b7a5b2cf04..7cfd754f72d8e 100644
--- a/src/test/ui/issues/issue-13359.stderr
+++ b/src/test/ui/issues/issue-13359.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     foo(1*(1 as isize));
    |         ^^^^^^^^^^^^^^ expected i16, found isize
-help: you can convert an `isize` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo((1*(1 as isize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     bar(1*(1 as usize));
    |         ^^^^^^^^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     bar((1*(1 as usize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-31910.stderr b/src/test/ui/issues/issue-31910.stderr
index 8dd9287ffec79..e7555b958a3d4 100644
--- a/src/test/ui/issues/issue-31910.stderr
+++ b/src/test/ui/issues/issue-31910.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     X = Trait::Number,
    |         ^^^^^^^^^^^^^ expected isize, found i32
-help: you can convert an `i32` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     X = Trait::Number.try_into().unwrap(),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-45697-1.stderr b/src/test/ui/issues/issue-45697-1.stderr
index 854e18003f330..30c69f19658c8 100644
--- a/src/test/ui/issues/issue-45697-1.stderr
+++ b/src/test/ui/issues/issue-45697-1.stderr
@@ -1,12 +1,4 @@
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
-  --> $DIR/issue-45697-1.rs:20:9
-   |
-LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                        - borrow of `*y.pointer` occurs here
-LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -17,7 +9,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -28,7 +20,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0503, E0506.
 For more information about an error, try `rustc --explain E0503`.
diff --git a/src/test/ui/issues/issue-45697.stderr b/src/test/ui/issues/issue-45697.stderr
index 01ae416b1cf14..26749d36f0b7b 100644
--- a/src/test/ui/issues/issue-45697.stderr
+++ b/src/test/ui/issues/issue-45697.stderr
@@ -1,12 +1,4 @@
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
-  --> $DIR/issue-45697.rs:20:9
-   |
-LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                        - borrow of `*y.pointer` occurs here
-LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -17,7 +9,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
@@ -28,7 +20,7 @@ LL |         *y.pointer += 1;
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0503, E0506.
 For more information about an error, try `rustc --explain E0503`.
diff --git a/src/test/ui/issues/issue-46471-1.stderr b/src/test/ui/issues/issue-46471-1.stderr
index 51026c9f2d834..b09f31729a5fd 100644
--- a/src/test/ui/issues/issue-46471-1.stderr
+++ b/src/test/ui/issues/issue-46471-1.stderr
@@ -1,16 +1,5 @@
-error[E0597]: `z` does not live long enough (Ast)
-  --> $DIR/issue-46471-1.rs:6:14
-   |
-LL |         &mut z
-   |              ^ borrowed value does not live long enough
-LL |     };
-   |     - `z` dropped here while still borrowed
-...
-LL | }
-   | - borrowed value needs to live until here
-
-error[E0597]: `z` does not live long enough (Mir)
-  --> $DIR/issue-46471-1.rs:6:9
+error[E0597]: `z` does not live long enough
+  --> $DIR/issue-46471-1.rs:4:9
    |
 LL |         &mut z
    |         ^^^^^^
@@ -20,6 +9,6 @@ LL |         &mut z
 LL |     };
    |     - `z` dropped here while still borrowed
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issues/issue-46471.stderr b/src/test/ui/issues/issue-46471.stderr
index 90202e307eb11..935414c1f3f9d 100644
--- a/src/test/ui/issues/issue-46471.stderr
+++ b/src/test/ui/issues/issue-46471.stderr
@@ -1,21 +1,9 @@
-error[E0597]: `x` does not live long enough (Ast)
-  --> $DIR/issue-46471.rs:5:6
-   |
-LL |     &x
-   |      ^ borrowed value does not live long enough
-...
-LL | }
-   | - borrowed value only lives until here
-   |
-   = note: borrowed value must be valid for the static lifetime...
-
-error[E0515]: cannot return reference to local variable `x` (Mir)
-  --> $DIR/issue-46471.rs:5:5
+error[E0515]: cannot return reference to local variable `x`
+  --> $DIR/issue-46471.rs:3:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/issues/issue-46472.stderr b/src/test/ui/issues/issue-46472.stderr
index 0cc93a081b2af..6e561e03a8b7a 100644
--- a/src/test/ui/issues/issue-46472.stderr
+++ b/src/test/ui/issues/issue-46472.stderr
@@ -1,20 +1,5 @@
-error[E0597]: borrowed value does not live long enough (Ast)
-  --> $DIR/issue-46472.rs:4:10
-   |
-LL |     &mut 4
-   |          ^ temporary value does not live long enough
-...
-LL | }
-   | - temporary value only lives until here
-   |
-note: borrowed value must be valid for the lifetime 'a as defined on the function body at 3:8...
-  --> $DIR/issue-46472.rs:3:8
-   |
-LL | fn bar<'a>() -> &'a mut u32 {
-   |        ^^
-
-error[E0515]: cannot return reference to temporary value (Mir)
-  --> $DIR/issue-46472.rs:4:5
+error[E0515]: cannot return reference to temporary value
+  --> $DIR/issue-46472.rs:2:5
    |
 LL |     &mut 4
    |     ^^^^^-
@@ -22,7 +7,6 @@ LL |     &mut 4
    |     |    temporary value created here
    |     returns a reference to data owned by the current function
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
index e15290f0b9ee9..c646912d3b679 100644
--- a/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
@@ -1,36 +1,5 @@
-error[E0384]: cannot assign twice to immutable variable `x` (Ast)
-  --> $DIR/liveness-assign-imm-local-notes.rs:13:9
-   |
-LL |         x = 2;
-   |         ----- first assignment to `x`
-LL |         x = 3;
-   |         ^^^^^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign twice to immutable variable `x` (Ast)
-  --> $DIR/liveness-assign-imm-local-notes.rs:25:13
-   |
-LL |             x = 2;
-   |             ----- first assignment to `x`
-LL |             x = 3;
-   |             ^^^^^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign twice to immutable variable `x` (Ast)
-  --> $DIR/liveness-assign-imm-local-notes.rs:35:13
-   |
-LL |             x = 1;
-   |             ^^^^^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign twice to immutable variable `x` (Ast)
-  --> $DIR/liveness-assign-imm-local-notes.rs:38:13
-   |
-LL |             x = 1;
-   |             ----- first assignment to `x`
-...
-LL |             x = 2;
-   |             ^^^^^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign twice to immutable variable `x` (Mir)
-  --> $DIR/liveness-assign-imm-local-notes.rs:13:9
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/liveness-assign-imm-local-notes.rs:10:9
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
@@ -40,8 +9,8 @@ LL |         x = 2;
 LL |         x = 3;
    |         ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x` (Mir)
-  --> $DIR/liveness-assign-imm-local-notes.rs:25:13
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/liveness-assign-imm-local-notes.rs:21:13
    |
 LL |         let x;
    |             - help: make this binding mutable: `mut x`
@@ -51,8 +20,8 @@ LL |             x = 2;
 LL |             x = 3;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x` (Mir)
-  --> $DIR/liveness-assign-imm-local-notes.rs:35:13
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/liveness-assign-imm-local-notes.rs:30:13
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
@@ -60,18 +29,18 @@ LL |     let x;
 LL |             x = 1;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error[E0384]: cannot assign twice to immutable variable `x` (Mir)
-  --> $DIR/liveness-assign-imm-local-notes.rs:38:13
+error[E0384]: cannot assign twice to immutable variable `x`
+  --> $DIR/liveness-assign-imm-local-notes.rs:32:13
    |
 LL |     let x;
    |         - help: make this binding mutable: `mut x`
 ...
 LL |             x = 1;
    |             ----- first assignment to `x`
-...
+LL |         } else {
 LL |             x = 2;
    |             ^^^^^ cannot assign twice to immutable variable
 
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index 49c72a655e57a..b1bd749bef4a2 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
    |
 LL |     let y: usize = x.foo();
    |                    ^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     let y: usize = x.foo().try_into().unwrap();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index 1a81df8e2c464..881d9fd32029e 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -6,7 +6,7 @@ LL |                   $arr.len() * size_of($arr[0]));
 ...
 LL |     write!(hello);
    |     -------------- in this macro invocation
-help: you can convert an `usize` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
    |
 LL |                   ($arr.len() * size_of($arr[0])).try_into().unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr
index c49dbdab40210..2e1ddbdf57f98 100644
--- a/src/test/ui/moves/moves-based-on-type-tuple.stderr
+++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr
@@ -1,15 +1,5 @@
-error[E0382]: use of moved value: `x` (Ast)
-  --> $DIR/moves-based-on-type-tuple.rs:6:13
-   |
-LL |     box (x, x)
-   |          -  ^ value used here after move
-   |          |
-   |          value moved here
-   |
-   = note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `x` (Mir)
-  --> $DIR/moves-based-on-type-tuple.rs:6:13
+error[E0382]: use of moved value: `x`
+  --> $DIR/moves-based-on-type-tuple.rs:4:13
    |
 LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
    |        - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
@@ -18,6 +8,6 @@ LL |     box (x, x)
    |          |
    |          value moved here
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr
index abb5343845b57..af79771e7e1b9 100644
--- a/src/test/ui/nll/get_default.stderr
+++ b/src/test/ui/nll/get_default.stderr
@@ -1,41 +1,5 @@
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:23:17
-   |
-LL |         match map.get() {
-   |               --- immutable borrow occurs here
-...
-LL |                 map.set(String::new()); // Ideally, this would not error.
-   |                 ^^^ mutable borrow occurs here
-...
-LL | }
-   | - immutable borrow ends here
-
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:35:17
-   |
-LL |         match map.get() {
-   |               --- immutable borrow occurs here
-LL |             Some(v) => {
-LL |                 map.set(String::new()); // Both AST and MIR error here
-   |                 ^^^ mutable borrow occurs here
-...
-LL | }
-   | - immutable borrow ends here
-
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:41:17
-   |
-LL |         match map.get() {
-   |               --- immutable borrow occurs here
-...
-LL |                 map.set(String::new()); // Ideally, just AST would error here
-   |                 ^^^ mutable borrow occurs here
-...
-LL | }
-   | - immutable borrow ends here
-
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:23:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:21:17
    |
 LL | fn ok(map: &mut Map) -> &String {
    |            - let's call the lifetime of this reference `'1`
@@ -47,10 +11,10 @@ LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 ...
 LL |                 map.set(String::new()); // Ideally, this would not error.
-   |                 ^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:35:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:32:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -59,13 +23,13 @@ LL |         match map.get() {
    |               --- immutable borrow occurs here
 LL |             Some(v) => {
 LL |                 map.set(String::new()); // Both AST and MIR error here
-   |                 ^^^ mutable borrow occurs here
-...
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |
 LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 
-error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:41:17
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:37:17
    |
 LL | fn err(map: &mut Map) -> &String {
    |             - let's call the lifetime of this reference `'1`
@@ -77,8 +41,8 @@ LL |                 return v;
    |                        - returning this value requires that `*map` is borrowed for `'1`
 ...
 LL |                 map.set(String::new()); // Ideally, just AST would error here
-   |                 ^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.stderr b/src/test/ui/nll/loan_ends_mid_block_pair.stderr
index 85703bda31c4e..eb8442b31d7c7 100644
--- a/src/test/ui/nll/loan_ends_mid_block_pair.stderr
+++ b/src/test/ui/nll/loan_ends_mid_block_pair.stderr
@@ -1,59 +1,5 @@
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:14:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-LL |     capitalize(c);
-LL |     data.0 = 'e';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:17:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-...
-LL |     data.0 = 'f';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:19:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-...
-LL |     data.0 = 'g';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:28:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-LL |     capitalize(c);
-LL |     data.0 = 'e';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:30:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-...
-LL |     data.0 = 'f';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Ast)
-  --> $DIR/loan_ends_mid_block_pair.rs:32:5
-   |
-LL |     let c = &mut data.0;
-   |                  ------ borrow of `data.0` occurs here
-...
-LL |     data.0 = 'g';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
-
-error[E0506]: cannot assign to `data.0` because it is borrowed (Mir)
-  --> $DIR/loan_ends_mid_block_pair.rs:14:5
+error[E0506]: cannot assign to `data.0` because it is borrowed
+  --> $DIR/loan_ends_mid_block_pair.rs:12:5
    |
 LL |     let c = &mut data.0;
    |             ----------- borrow of `data.0` occurs here
@@ -64,6 +10,6 @@ LL |     data.0 = 'e';
 LL |     capitalize(c);
    |                - borrow later used here
 
-error: aborting due to 7 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/nll/loan_ends_mid_block_vec.stderr b/src/test/ui/nll/loan_ends_mid_block_vec.stderr
index a3f1391f00140..c0b97bea348c4 100644
--- a/src/test/ui/nll/loan_ends_mid_block_vec.stderr
+++ b/src/test/ui/nll/loan_ends_mid_block_vec.stderr
@@ -1,77 +1,5 @@
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:13:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-LL |     capitalize(slice);
-LL |     data.push('d');
-   |     ^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:16:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-...
-LL |     data.push('e');
-   |     ^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:19:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-...
-LL |     data.push('f');
-   |     ^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:29:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-LL |     capitalize(slice);
-LL |     data.push('d');
-   |     ^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:31:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-...
-LL |     data.push('e');
-   |     ^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Ast)
-  --> $DIR/loan_ends_mid_block_vec.rs:33:5
-   |
-LL |     let slice = &mut data;
-   |                      ---- first mutable borrow occurs here
-...
-LL |     data.push('f');
-   |     ^^^^ second mutable borrow occurs here
-LL |
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
-  --> $DIR/loan_ends_mid_block_vec.rs:13:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+  --> $DIR/loan_ends_mid_block_vec.rs:11:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
@@ -82,8 +10,8 @@ LL |     data.push('d');
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
-  --> $DIR/loan_ends_mid_block_vec.rs:16:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+  --> $DIR/loan_ends_mid_block_vec.rs:13:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
@@ -94,18 +22,18 @@ LL |     data.push('e');
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error[E0499]: cannot borrow `data` as mutable more than once at a time (Mir)
-  --> $DIR/loan_ends_mid_block_vec.rs:19:5
+error[E0499]: cannot borrow `data` as mutable more than once at a time
+  --> $DIR/loan_ends_mid_block_vec.rs:15:5
    |
 LL |     let slice = &mut data;
    |                 --------- first mutable borrow occurs here
 ...
 LL |     data.push('f');
    |     ^^^^ second mutable borrow occurs here
-...
+LL |
 LL |     capitalize(slice);
    |                ----- first borrow later used here
 
-error: aborting due to 9 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/nll/region-ends-after-if-condition.stderr b/src/test/ui/nll/region-ends-after-if-condition.stderr
index aa876a0bcb3bf..c03e385790616 100644
--- a/src/test/ui/nll/region-ends-after-if-condition.stderr
+++ b/src/test/ui/nll/region-ends-after-if-condition.stderr
@@ -1,39 +1,15 @@
-error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/region-ends-after-if-condition.rs:19:9
-   |
-LL |     let value = &my_struct.field;
-   |                  --------------- immutable borrow occurs here
-LL |     if value.is_empty() {
-LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
-...
-LL | }
-   | - immutable borrow ends here
-
-error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/region-ends-after-if-condition.rs:29:9
-   |
-LL |     let value = &my_struct.field;
-   |                  --------------- immutable borrow occurs here
-LL |     if value.is_empty() {
-LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
-...
-LL | }
-   | - immutable borrow ends here
-
-error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/region-ends-after-if-condition.rs:29:9
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable
+  --> $DIR/region-ends-after-if-condition.rs:26:9
    |
 LL |     let value = &my_struct.field;
    |                 ---------------- immutable borrow occurs here
 LL |     if value.is_empty() {
 LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
 ...
 LL |     drop(value);
    |          ----- immutable borrow later used here
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/return_from_loop.stderr b/src/test/ui/nll/return_from_loop.stderr
index 09882d55cb70e..efd56ea2dd542 100644
--- a/src/test/ui/nll/return_from_loop.stderr
+++ b/src/test/ui/nll/return_from_loop.stderr
@@ -1,39 +1,15 @@
-error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast)
-  --> $DIR/return_from_loop.rs:22:9
-   |
-LL |     let value = &mut my_struct.field;
-   |                      --------------- first mutable borrow occurs here
-LL |     loop {
-LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Ast)
-  --> $DIR/return_from_loop.rs:35:9
-   |
-LL |     let value = &mut my_struct.field;
-   |                      --------------- first mutable borrow occurs here
-LL |     loop {
-LL |         my_struct.field.push_str("Hello, world!");
-   |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
-...
-LL | }
-   | - first borrow ends here
-
-error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time (Mir)
-  --> $DIR/return_from_loop.rs:22:9
+error[E0499]: cannot borrow `my_struct.field` as mutable more than once at a time
+  --> $DIR/return_from_loop.rs:20:9
    |
 LL |     let value = &mut my_struct.field;
    |                 -------------------- first mutable borrow occurs here
 LL |     loop {
 LL |         my_struct.field.push_str("Hello, world!");
    |         ^^^^^^^^^^^^^^^ second mutable borrow occurs here
-...
+LL |
 LL |         value.len();
    |         ----- first borrow later used here
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr
index ead3a79da0270..3f69bcc7d4a2f 100644
--- a/src/test/ui/numeric/const-scope.stderr
+++ b/src/test/ui/numeric/const-scope.stderr
@@ -37,7 +37,7 @@ error[E0308]: mismatched types
    |
 LL |     let d: i8 = c;
    |                 ^ expected i8, found i32
-help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     let d: i8 = c.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr
index 5a9349b4c0f29..c767bdd9bd5a5 100644
--- a/src/test/ui/numeric/len.stderr
+++ b/src/test/ui/numeric/len.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     test(array.len());
    |          ^^^^^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     test(array.len().try_into().unwrap());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr
index be4411e630bec..f58389ce96c3b 100644
--- a/src/test/ui/numeric/numeric-cast-2.stderr
+++ b/src/test/ui/numeric/numeric-cast-2.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     let x: u16 = foo();
    |                  ^^^^^ expected u16, found i32
-help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     let x: u16 = foo().try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     let y: i64 = x + x;
    |                  ^^^^^ expected i64, found u16
-help: you can convert an `u16` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     let y: i64 = (x + x).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     let z: i32 = x + x;
    |                  ^^^^^ expected i32, found u16
-help: you can convert an `u16` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     let z: i32 = (x + x).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr
index 9e7dcf7e41b55..e66b83f2b39f5 100644
--- a/src/test/ui/numeric/numeric-cast.stderr
+++ b/src/test/ui/numeric/numeric-cast.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u64);
    |                  ^^^^^ expected usize, found u64
-help: you can convert an `u64` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u32);
    |                  ^^^^^ expected usize, found u32
-help: you can convert an `u32` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u16);
    |                  ^^^^^ expected usize, found u16
-help: you can convert an `u16` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_u8);
    |                  ^^^^ expected usize, found u8
-help: you can convert an `u8` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_u8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_isize);
    |                  ^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_isize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i64);
    |                  ^^^^^ expected usize, found i64
-help: you can convert an `i64` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i32);
    |                  ^^^^^ expected usize, found i32
-help: you can convert an `i32` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i16);
    |                  ^^^^^ expected usize, found i16
-help: you can convert an `i16` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<usize>(x_i8);
    |                  ^^^^ expected usize, found i8
-help: you can convert an `i8` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<usize>(x_i8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -93,7 +93,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_usize);
    |                  ^^^^^^^ expected isize, found usize
-help: you can convert an `usize` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_usize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u64);
    |                  ^^^^^ expected isize, found u64
-help: you can convert an `u64` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +113,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u32);
    |                  ^^^^^ expected isize, found u32
-help: you can convert an `u32` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,7 +123,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u16);
    |                  ^^^^^ expected isize, found u16
-help: you can convert an `u16` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_u8);
    |                  ^^^^ expected isize, found u8
-help: you can convert an `u8` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_u8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,7 +143,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i64);
    |                  ^^^^^ expected isize, found i64
-help: you can convert an `i64` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i32);
    |                  ^^^^^ expected isize, found i32
-help: you can convert an `i32` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i16);
    |                  ^^^^^ expected isize, found i16
-help: you can convert an `i16` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<isize>(x_i8);
    |                  ^^^^ expected isize, found i8
-help: you can convert an `i8` to `isize` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `isize` and panic if the converted value wouldn't fit
    |
 LL |     foo::<isize>(x_i8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -183,7 +183,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_usize);
    |                ^^^^^^^ expected u64, found usize
-help: you can convert an `usize` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_isize);
    |                ^^^^^^^ expected u64, found isize
-help: you can convert an `isize` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -230,7 +230,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i64);
    |                ^^^^^ expected u64, found i64
-help: you can convert an `i64` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -240,7 +240,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i32);
    |                ^^^^^ expected u64, found i32
-help: you can convert an `i32` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i16);
    |                ^^^^^ expected u64, found i16
-help: you can convert an `i16` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +260,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u64>(x_i8);
    |                ^^^^ expected u64, found i8
-help: you can convert an `i8` to `u64` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u64>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_usize);
    |                ^^^^^^^ expected i64, found usize
-help: you can convert an `usize` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u64);
    |                ^^^^^ expected i64, found u64
-help: you can convert an `u64` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -290,7 +290,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u32);
    |                ^^^^^ expected i64, found u32
-help: you can convert an `u32` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -300,7 +300,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u16);
    |                ^^^^^ expected i64, found u16
-help: you can convert an `u16` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -310,7 +310,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_u8);
    |                ^^^^ expected i64, found u8
-help: you can convert an `u8` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -320,7 +320,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i64>(x_isize);
    |                ^^^^^^^ expected i64, found isize
-help: you can convert an `isize` to `i64` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -357,7 +357,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_usize);
    |                ^^^^^^^ expected u32, found usize
-help: you can convert an `usize` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_u64);
    |                ^^^^^ expected u32, found u64
-help: you can convert an `u64` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -395,7 +395,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_isize);
    |                ^^^^^^^ expected u32, found isize
-help: you can convert an `isize` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +405,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i64);
    |                ^^^^^ expected u32, found i64
-help: you can convert an `i64` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -415,7 +415,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i32);
    |                ^^^^^ expected u32, found i32
-help: you can convert an `i32` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -425,7 +425,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i16);
    |                ^^^^^ expected u32, found i16
-help: you can convert an `i16` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -435,7 +435,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u32>(x_i8);
    |                ^^^^ expected u32, found i8
-help: you can convert an `i8` to `u32` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u32>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -445,7 +445,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_usize);
    |                ^^^^^^^ expected i32, found usize
-help: you can convert an `usize` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -455,7 +455,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u64);
    |                ^^^^^ expected i32, found u64
-help: you can convert an `u64` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -465,7 +465,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u32);
    |                ^^^^^ expected i32, found u32
-help: you can convert an `u32` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,7 +475,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u16);
    |                ^^^^^ expected i32, found u16
-help: you can convert an `u16` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -485,7 +485,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_u8);
    |                ^^^^ expected i32, found u8
-help: you can convert an `u8` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -495,7 +495,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_isize);
    |                ^^^^^^^ expected i32, found isize
-help: you can convert an `isize` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -505,7 +505,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i32>(x_i64);
    |                ^^^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -533,7 +533,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_usize);
    |                ^^^^^^^ expected u16, found usize
-help: you can convert an `usize` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -543,7 +543,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_u64);
    |                ^^^^^ expected u16, found u64
-help: you can convert an `u64` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -553,7 +553,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_u32);
    |                ^^^^^ expected u16, found u32
-help: you can convert an `u32` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -572,7 +572,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_isize);
    |                ^^^^^^^ expected u16, found isize
-help: you can convert an `isize` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -582,7 +582,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i64);
    |                ^^^^^ expected u16, found i64
-help: you can convert an `i64` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -592,7 +592,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i32);
    |                ^^^^^ expected u16, found i32
-help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -602,7 +602,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i16);
    |                ^^^^^ expected u16, found i16
-help: you can convert an `i16` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -612,7 +612,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u16>(x_i8);
    |                ^^^^ expected u16, found i8
-help: you can convert an `i8` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u16>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -622,7 +622,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_usize);
    |                ^^^^^^^ expected i16, found usize
-help: you can convert an `usize` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -632,7 +632,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u64);
    |                ^^^^^ expected i16, found u64
-help: you can convert an `u64` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -642,7 +642,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u32);
    |                ^^^^^ expected i16, found u32
-help: you can convert an `u32` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -652,7 +652,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u16);
    |                ^^^^^ expected i16, found u16
-help: you can convert an `u16` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_u8);
    |                ^^^^ expected i16, found u8
-help: you can convert an `u8` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_u8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -672,7 +672,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_isize);
    |                ^^^^^^^ expected i16, found isize
-help: you can convert an `isize` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -682,7 +682,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_i64);
    |                ^^^^^ expected i16, found i64
-help: you can convert an `i64` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -692,7 +692,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i16>(x_i32);
    |                ^^^^^ expected i16, found i32
-help: you can convert an `i32` to `i16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -711,7 +711,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_usize);
    |               ^^^^^^^ expected u8, found usize
-help: you can convert an `usize` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -721,7 +721,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u64);
    |               ^^^^^ expected u8, found u64
-help: you can convert an `u64` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -731,7 +731,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u32);
    |               ^^^^^ expected u8, found u32
-help: you can convert an `u32` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -741,7 +741,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_u16);
    |               ^^^^^ expected u8, found u16
-help: you can convert an `u16` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -751,7 +751,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_isize);
    |               ^^^^^^^ expected u8, found isize
-help: you can convert an `isize` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -761,7 +761,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i64);
    |               ^^^^^ expected u8, found i64
-help: you can convert an `i64` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -771,7 +771,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i32);
    |               ^^^^^ expected u8, found i32
-help: you can convert an `i32` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -781,7 +781,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i16);
    |               ^^^^^ expected u8, found i16
-help: you can convert an `i16` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -791,7 +791,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<u8>(x_i8);
    |               ^^^^ expected u8, found i8
-help: you can convert an `i8` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<u8>(x_i8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -801,7 +801,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_usize);
    |               ^^^^^^^ expected i8, found usize
-help: you can convert an `usize` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -811,7 +811,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u64);
    |               ^^^^^ expected i8, found u64
-help: you can convert an `u64` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -821,7 +821,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u32);
    |               ^^^^^ expected i8, found u32
-help: you can convert an `u32` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -831,7 +831,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u16);
    |               ^^^^^ expected i8, found u16
-help: you can convert an `u16` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -841,7 +841,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_u8);
    |               ^^^^ expected i8, found u8
-help: you can convert an `u8` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_u8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -851,7 +851,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_isize);
    |               ^^^^^^^ expected i8, found isize
-help: you can convert an `isize` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -861,7 +861,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i64);
    |               ^^^^^ expected i8, found i64
-help: you can convert an `i64` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -871,7 +871,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i32);
    |               ^^^^^ expected i8, found i32
-help: you can convert an `i32` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -881,7 +881,7 @@ error[E0308]: mismatched types
    |
 LL |     foo::<i8>(x_i16);
    |               ^^^^^ expected i8, found i16
-help: you can convert an `i16` to `i8` or panic if it the converted value wouldn't fit
+help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
    |
 LL |     foo::<i8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr
index fabaea0535f5b..c4f6e0212621f 100644
--- a/src/test/ui/pattern/const-pat-ice.stderr
+++ b/src/test/ui/pattern/const-pat-ice.stderr
@@ -1,5 +1,5 @@
 thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1085:5
-note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
 
diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr
index 7eeefa9550543..596264ba16b42 100644
--- a/src/test/ui/pub/pub-restricted.stderr
+++ b/src/test/ui/pub/pub-restricted.stderr
@@ -21,7 +21,18 @@ LL | pub (b) fn bfn() {}
            `pub(in path::to::module)`: visible only on the specified path
 
 error[E0704]: incorrect visibility restriction
-  --> $DIR/pub-restricted.rs:22:14
+  --> $DIR/pub-restricted.rs:7:6
+   |
+LL | pub (crate::a) fn cfn() {}
+   |      ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a`
+   |
+   = help: some possible visibility restrictions are:
+           `pub(crate)`: visible only on the current crate
+           `pub(super)`: visible only in the current module's parent
+           `pub(in path::to::module)`: visible only on the specified path
+
+error[E0704]: incorrect visibility restriction
+  --> $DIR/pub-restricted.rs:24:14
    |
 LL |         pub (a) invalid: usize,
    |              ^ help: make this visible only to module `a` with `in`: `in a`
@@ -32,7 +43,7 @@ LL |         pub (a) invalid: usize,
            `pub(in path::to::module)`: visible only on the specified path
 
 error[E0704]: incorrect visibility restriction
-  --> $DIR/pub-restricted.rs:31:6
+  --> $DIR/pub-restricted.rs:33:6
    |
 LL | pub (xyz) fn xyz() {}
    |      ^^^ help: make this visible only to module `xyz` with `in`: `in xyz`
@@ -43,11 +54,11 @@ LL | pub (xyz) fn xyz() {}
            `pub(in path::to::module)`: visible only on the specified path
 
 error: visibilities can only be restricted to ancestor modules
-  --> $DIR/pub-restricted.rs:23:17
+  --> $DIR/pub-restricted.rs:25:17
    |
 LL |         pub (in x) non_parent_invalid: usize,
    |                 ^
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0704`.
diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr
index 6772aa1c38d2c..df73ac0b182f0 100644
--- a/src/test/ui/repeat_count.stderr
+++ b/src/test/ui/repeat_count.stderr
@@ -42,7 +42,7 @@ error[E0308]: mismatched types
    |
 LL |     let f = [0; -4_isize];
    |                 ^^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     let f = [0; (-4_isize).try_into().unwrap()];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ error[E0308]: mismatched types
    |
 LL |     let f = [0_usize; -1_isize];
    |                       ^^^^^^^^ expected usize, found isize
-help: you can convert an `isize` to `usize` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
    |
 LL |     let f = [0_usize; (-1_isize).try_into().unwrap()];
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr
index 97523fe82cd4e..409fabb951adc 100644
--- a/src/test/ui/shift-various-bad-types.stderr
+++ b/src/test/ui/shift-various-bad-types.stderr
@@ -27,7 +27,7 @@ error[E0308]: mismatched types
    |
 LL |     let _: i32 = 22_i64 >> 1_i32;
    |                  ^^^^^^^^^^^^^^^ expected i32, found i64
-help: you can convert an `i64` to `i32` or panic if it the converted value wouldn't fit
+help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
    |
 LL |     let _: i32 = (22_i64 >> 1_i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr
index 6ddd93d632e15..7539cbada8b7b 100644
--- a/src/test/ui/symbol-names/basic.stderr
+++ b/src/test/ui/symbol-names/basic.stderr
@@ -1,4 +1,4 @@
-error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
+error: symbol-name(_ZN5basic4main17hd72940ef9669d526E)
   --> $DIR/basic.rs:3:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr
index eda8646b5b4de..20e48782a3a9e 100644
--- a/src/test/ui/symbol-names/impl1.stderr
+++ b/src/test/ui/symbol-names/impl1.stderr
@@ -1,4 +1,4 @@
-error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
+error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE)
   --> $DIR/impl1.rs:8:9
    |
 LL |         #[rustc_symbol_name]
@@ -10,7 +10,7 @@ error: def-path(foo::Foo::bar)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E)
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E)
   --> $DIR/impl1.rs:18:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
index 9acd63c2c25f1..e9c28248044f9 100644
--- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
+++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
@@ -6,7 +6,7 @@ LL | fn global_bound_is_hidden() -> u8
 ...
 LL |     B::get_x()
    |     ^^^^^^^^^^ expected u8, found i32
-help: you can convert an `i32` to `u8` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
    |
 LL |     B::get_x().try_into().unwrap()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr
index f51f2defd4759..f3e1cc41cada2 100644
--- a/src/test/ui/tutorial-suffix-inference-test.stderr
+++ b/src/test/ui/tutorial-suffix-inference-test.stderr
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
    |
 LL |     identity_u16(y);
    |                  ^ expected u16, found i32
-help: you can convert an `i32` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     identity_u16(y.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ error[E0308]: mismatched types
    |
 LL |     identity_u16(a);
    |                  ^ expected u16, found isize
-help: you can convert an `isize` to `u16` or panic if it the converted value wouldn't fit
+help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
    |
 LL |     identity_u16(a.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^

From 2cdd7f8387bf1dc08bbd1c11abd83cb1f892e6cd Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Sun, 2 Jun 2019 19:31:55 +0100
Subject: [PATCH 15/24] Removed unnecessary nested-lifetime-bounds test.

---
 .../nested-lifetime-bounds.rs                 | 25 -------------------
 .../nested-lifetime-bounds.stderr             |  8 ------
 2 files changed, 33 deletions(-)
 delete mode 100644 src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
 delete mode 100644 src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr

diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
deleted file mode 100644
index 25c2c2916f3bc..0000000000000
--- a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// compile-fail
-
-#![feature(associated_type_bounds)]
-
-use std::fmt::Debug;
-
-trait Lam<Binder> { type App; }
-
-fn nested_bounds<_0, _1, _2, D>()
-where
-    D: Clone + Iterator<Item: Send + for<'a> Iterator<Item: for<'b> Lam<&'a &'b u8, App = _0>>>,
-    //~^ ERROR nested quantification of lifetimes [E0316]
-    _0: Debug,
-{}
-
-fn nested_bounds_desugared<_0, _1, _2, D>()
-where
-    D: Clone + Iterator<Item = _2>,
-    _2: Send + for<'a> Iterator,
-    for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
-    //~^ ERROR nested quantification of lifetimes [E0316]
-    _0: Debug,
-{}
-
-fn main() {}
diff --git a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr b/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
deleted file mode 100644
index db421e6973d07..0000000000000
--- a/src/test/ui/associated-type-bounds/nested-lifetime-bounds.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error[E0316]: nested quantification of lifetimes
-  --> $DIR/nested-lifetime-bounds.rs:20:37
-   |
-LL |     for<'a> <_2 as Iterator>::Item: for<'b> Lam<&'a &'b u8, App = _0>,
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-

From 963e22c38c97f342338b9d93ca5be58418fb535f Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 8 May 2019 15:58:42 -0400
Subject: [PATCH 16/24] added a few comments

---
 src/librustc_typeck/astconv.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 4a2949fa6b069..92c5df72d8c16 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -571,6 +571,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     /// Given the type/lifetime/const arguments provided to some path (along with
     /// an implicit `Self`, if this is a trait reference), returns the complete
     /// set of substitutions. This may involve applying defaulted type parameters.
+    /// Also returns back constriants on associated types.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
     fn create_substs_for_ast_path<'a>(&self,
@@ -1091,6 +1092,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 }), binding.span));
             }
             ConvertedBindingKind::Constraint(ref ast_bounds) => {
+                // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
+                //
+                // `<T as Iterator>::Item: Debug`
+                //
                 // Calling `skip_binder` is okay, because the predicates are re-bound later by
                 // `instantiate_poly_trait_ref`.
                 let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);

From 049f4d8cf4bf5613a658316afbec168fc03294ba Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Wed, 5 Jun 2019 20:57:44 +0100
Subject: [PATCH 17/24] document the `Bounds` struct a bit

---
 src/librustc_typeck/astconv.rs | 39 ++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 92c5df72d8c16..2ba6601e82631 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2287,17 +2287,52 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 }
 
-// A helper struct for conveniently grouping a set of bounds which we pass to
-// and return from functions in multiple places.
+/// Collects together a list of bounds that are applied to some type,
+/// after they've been converted into `ty` form (from the HIR
+/// representations). These lists of bounds occur in many places in
+/// Rust's syntax:
+///
+/// ```
+/// trait Foo: Bar + Baz { }
+///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
+///
+/// fn foo<T: Bar + Baz>() { }
+///           ^^^^^^^^^ bounding the type parameter `T`
+///
+/// impl dyn Bar + Baz
+///          ^^^^^^^^^ bounding the forgotten dynamic type
+/// ```
+///
+/// Our representation is a bit mixed here -- in some cases, we
+/// include the self type (e.g., `trait_bounds`) but in others we do
 #[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
+    /// A list of region bounds on the (implicit) self type. So if you
+    /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
+    /// the `T` is not explicitly included).
     pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,
+
+    /// A list of trait bounds. So if you had `T: Debug` this would be
+    /// `T: Debug`. Note that the self-type is explicit here.
     pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+
+    /// A list of projection equality bounds. So if you had `T:
+    /// Iterator<Item = u32>` this would include `<T as
+    /// Iterator>::Item => u32`. Note that the self-type is explicit
+    /// here.
     pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+
+    /// `Some` if there is *no* `?Sized` predicate. The `span`
+    /// is the location in the source of the `T` declaration which can
+    /// be cited as the source of the `T: Sized` requirement.
     pub implicitly_sized: Option<Span>,
 }
 
 impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
+    /// Converts a bounds list into a flat set of predicates (like
+    /// where-clauses). Because some of our bounds listings (e.g.,
+    /// regions) don't include the self-type, you must supply the
+    /// self-type here (the `param_ty` parameter).
     pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
                       -> Vec<(ty::Predicate<'tcx>, Span)>
     {

From f6ee542f16785fd944a663b8f4bc203ad150d2de Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Fri, 31 May 2019 17:14:36 -0400
Subject: [PATCH 18/24] make `instantiate_poly_trait_ref_inner` private to this
 module


From 83078f0b37fd944f09bcfce4f8d476814b936aae Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Fri, 31 May 2019 17:15:15 -0400
Subject: [PATCH 19/24] comment `instantiate_poly_trait_ref` and its binder
 behavior

---
 src/librustc_typeck/astconv.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 2ba6601e82631..28c5c13492aac 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -792,6 +792,25 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         (poly_trait_ref, potential_assoc_types)
     }
 
+    /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
+    /// a full trait reference. The resulting trait reference is returned. This may also generate
+    /// auxiliary bounds, which are added to `bounds`.
+    ///
+    /// Example:
+    ///
+    /// ```
+    /// poly_trait_ref = Iterator<Item = u32>
+    /// self_ty = Foo
+    /// ```
+    ///
+    /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
+    ///
+    /// **A note on binders:** against our usual convention, there is an implied bounder around
+    /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
+    /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
+    /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
+    /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
+    /// however.
     pub fn instantiate_poly_trait_ref(&self,
         poly_trait_ref: &hir::PolyTraitRef,
         self_ty: Ty<'tcx>,

From 18d5085bff5680fcd1027722ebaf71703384eb33 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Fri, 31 May 2019 17:30:44 -0400
Subject: [PATCH 20/24] more comments

---
 src/librustc_typeck/astconv.rs | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 28c5c13492aac..5873d0fe8229f 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -929,6 +929,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         true
     }
 
+    /// This helper takes a *converted* parameter type (`param_ty`)
+    /// and an *unconverted* list of bounds:
+    ///
+    /// ```
+    /// fn foo<T: Debug>
+    ///        ^  ^^^^^ `ast_bounds` parameter, in HIR form
+    ///        |
+    ///        `param_ty`, in ty form
+    /// ```
+    ///
+    /// It adds these `ast_bounds` into the `bounds` structure.
+    ///
+    /// **A note on binders:** There is an implied binder around
+    /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
+    /// for more details.
     fn add_bounds(&self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound],
@@ -962,9 +977,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         );
     }
 
-    /// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped
-    /// `Ty` or a region) to ty's notion of ty param bounds (which can either be user-defined traits
-    /// or the built-in trait `Sized`).
+    /// Translates a list of bounds from the HIR into the `Bounds` data structure.
+    /// The self-type for the bounds is given by `param_ty`.
+    ///
+    /// Example:
+    ///
+    /// ```
+    /// fn foo<T: Bar + Baz>() { }
+    ///        ^  ^^^^^^^^^ ast_bounds
+    ///        param_ty
+    /// ```
+    ///
+    /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
+    /// considered `Sized` unless there is an explicit `?Sized` bound.  This would be true in the
+    /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
+    ///
+    /// `span` should be the declaration size of the parameter.
     pub fn compute_bounds(&self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound],

From e48dd1257c54dda498f02ce7823b6d7fbf24c36a Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 5 Jun 2019 15:20:40 -0400
Subject: [PATCH 21/24] another comment

---
 src/librustc_typeck/astconv.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5873d0fe8229f..fc93d7ee61326 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -941,7 +941,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     ///
     /// It adds these `ast_bounds` into the `bounds` structure.
     ///
-    /// **A note on binders:** There is an implied binder around
+    /// **A note on binders:** there is an implied binder around
     /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
     /// for more details.
     fn add_bounds(&self,
@@ -1017,6 +1017,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         bounds
     }
 
+    /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
+    /// onto `bounds`.
+    ///
+    /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
+    /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
+    /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
     fn add_predicates_for_ast_type_binding(
         &self,
         hir_ref_id: hir::HirId,

From a90042718848e25a7df29621592250ccecf78b4d Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 5 Jun 2019 15:27:19 -0400
Subject: [PATCH 22/24] verified that skip-binder is ok

---
 src/librustc_typeck/astconv.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fc93d7ee61326..7f2d3c8e424b9 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1149,8 +1149,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 //
                 // `<T as Iterator>::Item: Debug`
                 //
-                // Calling `skip_binder` is okay, because the predicates are re-bound later by
-                // `instantiate_poly_trait_ref`.
+                // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
+                // parameter to have a skipped binder.
                 let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
                 self.add_bounds(
                     param_ty,

From e37a7a1f74afb0b62b933af4439d271f4b8f890a Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Wed, 5 Jun 2019 21:08:36 +0100
Subject: [PATCH 23/24] add an example to `create_substs_for_ast_path`

---
 src/librustc_typeck/astconv.rs | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7f2d3c8e424b9..34f817ba570e7 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -573,6 +573,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     /// set of substitutions. This may involve applying defaulted type parameters.
     /// Also returns back constriants on associated types.
     ///
+    /// Example:
+    ///
+    /// ```
+    /// T: std::ops::Index<usize, Output = u32>
+    /// ^1 ^^^^^^^^^^^^^^2 ^^^^3  ^^^^^^^^^^^4
+    /// ```
+    ///
+    /// 1. The `self_ty` here would refer to the type `T`.
+    /// 2. The path in question is the path to the trait `std::ops::Index`,
+    ///    which will have been resolved to a `def_id`
+    /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
+    ///    parameters are returned in the `SubstsRef`, the associated type bindings like
+    ///    `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
+    ///
     /// Note that the type listing given here is *exactly* what the user provided.
     fn create_substs_for_ast_path<'a>(&self,
         span: Span,

From ee890331f6e33afe12ef250eb6388db2aab7cbbf Mon Sep 17 00:00:00 2001
From: Alexander Regueiro <alexreg@me.com>
Date: Thu, 6 Jun 2019 03:28:53 +0100
Subject: [PATCH 24/24] Reblessed tests with NLL compare mode on.

---
 .../implied-region-constraints.nll.stderr     | 24 +++++++++++++++++++
 ...t_outlive_least_region_or_bound.nll.stderr |  4 ++--
 .../static-return-lifetime-infered.nll.stderr |  4 ++--
 3 files changed, 28 insertions(+), 4 deletions(-)
 create mode 100644 src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr

diff --git a/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr b/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr
new file mode 100644
index 0000000000000..32d099fce759e
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/implied-region-constraints.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/implied-region-constraints.rs:19:56
+   |
+LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
+   |            --  -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+...
+LL |     let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
+   |                                                        ^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/implied-region-constraints.rs:40:64
+   |
+LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
+   |             --  -- lifetime `'b` defined here
+   |             |
+   |             lifetime `'a` defined here
+...
+LL |             let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
+   |                                                                ^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index 4b7c04f1e4331..b1e4edd998094 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -5,7 +5,7 @@ LL | fn elided(x: &i32) -> impl Copy { x }
    |              -        ^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
    |              |
    |              let's call the lifetime of this reference `'1`
-help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                       ^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |             --                 ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
    |             |
    |             lifetime `'a` defined here
-help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                ^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
index 0bf120cf7ecc1..0736f25cb51bd 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
@@ -5,7 +5,7 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
    |                         -         ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
    |                         |
    |                         let's call the lifetime of this reference `'1`
-help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
    |                    --               ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
    |                    |
    |                    lifetime `'a` defined here
-help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^