From dfa581ff8747c1d5804a08e8201031a37c2ea14a Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Thu, 11 Feb 2021 20:46:58 +0000
Subject: [PATCH 01/20] Fix pretty printing of generic associated type
 constraints

---
 compiler/rustc_ast_pretty/src/pprust/state.rs | 1 +
 src/test/pretty/gat-bounds.rs                 | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 01e234c9be9..cbeaa6018d1 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -914,6 +914,7 @@ impl<'a> State<'a> {
 
     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
         self.print_ident(constraint.ident);
+        constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.s.space();
         match &constraint.kind {
             ast::AssocTyConstraintKind::Equality { ty } => {
diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs
index 789e4bc80ac..8877c6cc992 100644
--- a/src/test/pretty/gat-bounds.rs
+++ b/src/test/pretty/gat-bounds.rs
@@ -13,4 +13,6 @@ impl X for () {
     type Y<T> where Self: Sized = u32;
 }
 
+fn f<T: X<Y<()> = i32>>() {}
+
 fn main() { }

From 9bbd3e0f8e51beb4c3ea6674327b17cd9d38d9da Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Thu, 11 Feb 2021 21:02:27 +0000
Subject: [PATCH 02/20] Remove ProjectionTy::from_ref_and_name

---
 compiler/rustc_hir/src/lang_items.rs            |  1 +
 compiler/rustc_middle/src/ty/sty.rs             | 16 ----------------
 compiler/rustc_trait_selection/src/autoderef.rs | 10 ++++------
 library/core/src/ops/deref.rs                   |  1 +
 4 files changed, 6 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 26ce30cb511..a5222e5c702 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -238,6 +238,7 @@ language_item_table! {
 
     Deref,                   sym::deref,               deref_trait,                Target::Trait;
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait;
+    DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait;
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 04cc4db0bcf..8a8e70f76ce 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1112,22 +1112,6 @@ pub struct ProjectionTy<'tcx> {
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
-    /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
-    /// associated item named `item_name`.
-    pub fn from_ref_and_name(
-        tcx: TyCtxt<'_>,
-        trait_ref: ty::TraitRef<'tcx>,
-        item_name: Ident,
-    ) -> ProjectionTy<'tcx> {
-        let item_def_id = tcx
-            .associated_items(trait_ref.def_id)
-            .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
-            .unwrap()
-            .def_id;
-
-        ProjectionTy { substs: trait_ref.substs, item_def_id }
-    }
-
     /// Extracts the underlying trait reference from this projection.
     /// For example, if this is a projection of `<T as Iterator>::Item`,
     /// then this function would return a `T: Iterator` trait reference.
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 05b6c4a48de..3f24a33f7d5 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -6,7 +6,6 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -146,11 +145,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         let normalized_ty = fulfillcx.normalize_projection_type(
             &self.infcx,
             self.param_env,
-            ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                trait_ref,
-                Ident::with_dummy_span(sym::Target),
-            ),
+            ty::ProjectionTy {
+                item_def_id: tcx.lang_items().deref_target()?,
+                substs: trait_ref.substs,
+            },
             cause,
         );
         if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 245152e5490..2419771eae2 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -64,6 +64,7 @@ pub trait Deref {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_target"]
+    #[cfg_attr(not(bootstrap), lang = "deref_target")]
     type Target: ?Sized;
 
     /// Dereferences the value.

From 0bf1d73d229fdd0c22ef87b1c764c88cf35dd616 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:07:46 +0000
Subject: [PATCH 03/20] Don't go through TraitRef to relate projections

---
 compiler/rustc_infer/src/infer/at.rs          | 25 ++++++++++++++++++-
 .../src/traits/project.rs                     | 15 ++++++-----
 .../src/traits/select/mod.rs                  | 20 ++++++++-------
 3 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index a7749d33b7c..11ee8fb17ad 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
     fn to_trace(
+        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
+        let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
         Trace { at: self, trace, a_is_expected }
     }
 }
@@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+    fn to_trace(
+        tcx: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
+        let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+        TypeTrace {
+            cause: cause.clone(),
+            values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6908480f431..a38e3817a95 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -921,8 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
                 && infcx.probe(|_| {
                     selcx.match_projection_projections(
                         obligation,
-                        obligation_trait_ref,
-                        &data,
+                        data,
                         potentially_unnormalized_candidates,
                     )
                 });
@@ -1344,25 +1343,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         poly_cache_entry,
     );
 
-    let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
-    let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+    let cache_projection = cache_entry.projection_ty;
+    let obligation_projection = obligation.predicate;
     let mut nested_obligations = Vec::new();
-    let cache_trait_ref = if potentially_unnormalized_candidate {
+    let cache_projection = if potentially_unnormalized_candidate {
         ensure_sufficient_stack(|| {
             normalize_with_depth_to(
                 selcx,
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                cache_trait_ref,
+                cache_projection,
                 &mut nested_obligations,
             )
         })
     } else {
-        cache_trait_ref
+        cache_projection
     };
 
-    match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
+    match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 87c8099dc3a..f0970a48808 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,6 +32,7 @@ use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Constness;
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fast_reject;
@@ -1254,32 +1255,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub(super) fn match_projection_projections(
         &mut self,
         obligation: &ProjectionTyObligation<'tcx>,
-        obligation_trait_ref: &ty::TraitRef<'tcx>,
-        data: &PolyProjectionPredicate<'tcx>,
+        env_predicate: PolyProjectionPredicate<'tcx>,
         potentially_unnormalized_candidates: bool,
     ) -> bool {
         let mut nested_obligations = Vec::new();
-        let projection_ty = if potentially_unnormalized_candidates {
+        let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            LateBoundRegionConversionTime::HigherRankedType,
+            env_predicate,
+        );
+        let infer_projection = if potentially_unnormalized_candidates {
             ensure_sufficient_stack(|| {
                 project::normalize_with_depth_to(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    data.map_bound(|data| data.projection_ty),
+                    infer_predicate.projection_ty,
                     &mut nested_obligations,
                 )
             })
         } else {
-            data.map_bound(|data| data.projection_ty)
+            infer_predicate.projection_ty
         };
 
-        // FIXME(generic_associated_types): Compare the whole projections
-        let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
-        let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+            .sup(obligation.predicate, infer_projection)
             .map_or(false, |InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
                     TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),

From 9526c0c6e83f37deb1d48e9761ee9bee2ae94f60 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:32:46 +0000
Subject: [PATCH 04/20] Avoid `trait_ref` when lowering ExistentialProjections

---
 compiler/rustc_middle/src/ty/sty.rs      | 23 +++++++---
 compiler/rustc_typeck/src/astconv/mod.rs | 57 +++++++++++-------------
 2 files changed, 44 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8a8e70f76ce..388a5767870 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1477,12 +1477,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
     /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
     /// then this function would return a `exists T. T: Iterator` existential trait
     /// reference.
-    pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
-        // FIXME(generic_associated_types): substs is the substs of the
-        // associated type, which should be truncated to get the correct substs
-        // for the trait.
+    pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
         let def_id = tcx.associated_item(self.item_def_id).container.id();
-        ty::ExistentialTraitRef { def_id, substs: self.substs }
+        let subst_count = tcx.generics_of(def_id).count() - 1;
+        let substs = tcx.intern_substs(&self.substs[..subst_count]);
+        ty::ExistentialTraitRef { def_id, substs }
     }
 
     pub fn with_self_ty(
@@ -1501,6 +1500,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
             ty: self.ty,
         }
     }
+
+    pub fn erase_self_ty(
+        tcx: TyCtxt<'tcx>,
+        projection_predicate: ty::ProjectionPredicate<'tcx>,
+    ) -> Self {
+        // Assert there is a Self.
+        projection_predicate.projection_ty.substs.type_at(0);
+
+        Self {
+            item_def_id: projection_predicate.projection_ty.item_def_id,
+            substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+            ty: projection_predicate.ty,
+        }
+    }
 }
 
 impl<'tcx> PolyExistentialProjection<'tcx> {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 244eba8ad5e..aa496f8722e 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -985,10 +985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         //
         // We want to produce `<B as SuperTrait<i32>>::T == foo`.
 
-        debug!(
-            "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
-            hir_ref_id, trait_ref, binding, bounds
-        );
+        debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
         let tcx = self.tcx();
 
         let candidate =
@@ -1326,37 +1323,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         debug!("regular_traits: {:?}", regular_traits);
         debug!("auto_traits: {:?}", auto_traits);
 
-        // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
-        // removing the dummy `Self` type (`trait_object_dummy_self`).
-        let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
-            if trait_ref.self_ty() != dummy_self {
-                // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
-                // which picks up non-supertraits where clauses - but also, the object safety
-                // completely ignores trait aliases, which could be object safety hazards. We
-                // `delay_span_bug` here to avoid an ICE in stable even when the feature is
-                // disabled. (#66420)
-                tcx.sess.delay_span_bug(
-                    DUMMY_SP,
-                    &format!(
-                        "trait_ref_to_existential called on {:?} with non-dummy Self",
-                        trait_ref,
-                    ),
-                );
-            }
-            ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
-        };
-
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_trait_refs =
-            regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
+        let existential_trait_refs = regular_traits.iter().map(|i| {
+            i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+                if trait_ref.self_ty() != dummy_self {
+                    // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+                    // which picks up non-supertraits where clauses - but also, the object safety
+                    // completely ignores trait aliases, which could be object safety hazards. We
+                    // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+                    // disabled. (#66420)
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!(
+                            "trait_ref_to_existential called on {:?} with non-dummy Self",
+                            trait_ref,
+                        ),
+                    );
+                }
+                ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+            })
+        });
         let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
-                let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
-                ty::ExistentialProjection {
-                    ty: b.ty,
-                    item_def_id: b.projection_ty.item_def_id,
-                    substs: trait_ref.substs,
+                if b.projection_ty.self_ty() != dummy_self {
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
+                    );
                 }
+                ty::ExistentialProjection::erase_self_ty(tcx, b)
             })
         });
 

From 79f6f11816cbef2bba6f5da6d4a4f0aa10535b88 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:41:00 +0000
Subject: [PATCH 05/20] Remove some unnecessary `trait_ref` calls

---
 compiler/rustc_privacy/src/lib.rs             | 27 ++++++++++++++++---
 .../src/traits/fulfill.rs                     | 20 +++++++-------
 .../src/traits/object_safety.rs               |  6 +----
 .../src/constrained_generic_params.rs         |  2 +-
 4 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 631dcb60594..0c340b2faaa 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_trait(trait_ref)
     }
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.skeleton().visit_projection_ty(projection)
+    }
     fn visit_predicates(
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
@@ -101,6 +107,20 @@ where
         if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
     }
 
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<V::BreakTy> {
+        let (trait_ref, assoc_substs) =
+            projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
+        self.visit_trait(trait_ref)?;
+        if self.def_id_visitor.shallow() {
+            ControlFlow::CONTINUE
+        } else {
+            assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
+        }
+    }
+
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
         match predicate.kind().skip_binder() {
             ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
@@ -108,7 +128,7 @@ where
             }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 ty.visit_with(self)?;
-                self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
+                self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
                 ty.visit_with(self)
@@ -197,7 +217,7 @@ where
                     return ControlFlow::CONTINUE;
                 }
                 // This will also visit substs if necessary, so we don't need to recurse.
-                return self.visit_trait(proj.trait_ref(tcx));
+                return self.visit_projection_ty(proj);
             }
             ty::Dynamic(predicates, ..) => {
                 // All traits in the list are considered the "primary" part of the type
@@ -1204,10 +1224,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                let tcx = self.tcx;
                 if self.visit(poly_predicate.skip_binder().ty).is_break()
                     || self
-                        .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
+                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
                         .is_break()
                 {
                     return;
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index d4ced20f863..f3bbf901683 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,6 +6,7 @@ use rustc_errors::ErrorReported;
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
 use std::marker::PhantomData;
@@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 // only reason we can fail to make progress on
                 // trait selection is because we don't have enough
                 // information about the types in the trait.
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
+                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
                 );
 
                 debug!(
@@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
             Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
             Ok(Ok(None)) => {
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    project_obligation.predicate.to_poly_trait_ref(tcx),
+                    project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
                 );
                 ProcessResult::Unchanged
             }
@@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
     }
 }
 
-/// Returns the set of inference variables contained in a trait ref.
-fn trait_ref_infer_vars<'a, 'tcx>(
+/// Returns the set of inference variables contained in `substs`.
+fn substs_infer_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    substs: ty::Binder<SubstsRef<'tcx>>,
 ) -> Vec<TyOrConstInferVar<'tcx>> {
     selcx
         .infcx()
-        .resolve_vars_if_possible(trait_ref)
-        .skip_binder()
-        .substs
+        .resolve_vars_if_possible(substs)
+        .skip_binder() // ok because this check doesn't care about regions
         .iter()
         // FIXME(eddyb) try using `skip_current_subtree` to skip everything that
         // doesn't contain inference variables, not just the outermost level.
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index e155f0366e1..7de20e477fe 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -292,11 +292,7 @@ fn predicate_references_self(
             //
             // This is ALT2 in issue #56288, see that for discussion of the
             // possible alternatives.
-            if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
-                Some(sp)
-            } else {
-                None
-            }
+            if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
         }
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 95670b9bdb9..529de1a2874 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
+                let inputs = parameters_for(&projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
                 if !relies_only_on_inputs {
                     continue;

From dfee89f75545b4fadc559eee324afc8bb0bdc1be Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:44:43 +0000
Subject: [PATCH 06/20] Make ProjectionTy::trait_ref truncate substs again

Also make sure that type arguments of associated types are printed in
some error messages.
---
 compiler/rustc_middle/src/ty/error.rs         | 40 ++++++++++++++++---
 compiler/rustc_middle/src/ty/mod.rs           | 16 +++++++-
 compiler/rustc_middle/src/ty/sty.rs           | 37 ++++++++++++-----
 .../src/traits/error_reporting/mod.rs         |  3 +-
 compiler/rustc_traits/src/chalk/lowering.rs   |  7 +---
 compiler/rustc_typeck/src/check/closure.rs    | 14 +++----
 .../rustc_typeck/src/check/fn_ctxt/_impl.rs   |  7 ++--
 .../rustc_typeck/src/check/method/suggest.rs  | 33 ++++++++-------
 .../constraint-assoc-type-suggestion.rs       | 17 ++++++++
 .../constraint-assoc-type-suggestion.stderr   | 27 +++++++++++++
 .../method-unsatified-assoc-type-predicate.rs | 35 ++++++++++++++++
 ...hod-unsatified-assoc-type-predicate.stderr | 29 ++++++++++++++
 12 files changed, 216 insertions(+), 49 deletions(-)
 create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
 create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
 create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
 create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr

diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 1669c59d7f1..ff955244924 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,5 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, DiagnosticBuilder};
@@ -400,14 +401,22 @@ impl<'tcx> TyCtxt<'tcx> {
                         {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
-                            let trait_ref = proj.trait_ref(self);
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
                             let path =
                                 self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
                             let item_name = self.item_name(proj.item_def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
                             let path = if path.ends_with('>') {
-                                format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
                             } else {
-                                format!("{}<{} = {}>", path, item_name, p)
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
                             };
                             note = !suggest_constraining_type_param(
                                 self,
@@ -556,7 +565,7 @@ impl<T> Trait<T> for X {
         ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
-        let trait_ref = proj_ty.trait_ref(self);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
         if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
             if let Some(hir_generics) = item.generics() {
                 // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
@@ -590,6 +599,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             pred.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         ) {
@@ -607,6 +617,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             param.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         );
@@ -692,6 +703,7 @@ impl<T> Trait<T> for X {
                 db,
                 self.def_span(def_id),
                 &assoc,
+                proj_ty.trait_ref_and_own_substs(self).1,
                 values.found,
                 &msg,
             ) {
@@ -856,6 +868,7 @@ fn foo(&self) -> Self::T { String::new() }
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -865,7 +878,12 @@ fn foo(&self) -> Self::T { String::new() }
                 // Relate the type param against `T` in `<A as T>::Foo`.
                 ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
                     && self.constrain_associated_type_structured_suggestion(
-                        db, ptr.span, assoc, ty, msg,
+                        db,
+                        ptr.span,
+                        assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
                     )
             }
             _ => false,
@@ -879,6 +897,7 @@ fn foo(&self) -> Self::T { String::new() }
         db: &mut DiagnosticBuilder<'_>,
         span: Span,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -890,11 +909,20 @@ fn foo(&self) -> Self::T { String::new() }
                 let span = Span::new(pos, pos, span.ctxt());
                 (span, format!(", {} = {}", assoc.ident, ty))
             } else {
-                (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
             };
             db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
         }
         false
     }
+
+    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+        let mut item_args = String::new();
+        FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.");
+        item_args
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index babab005edb..b7f62437fa5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
         self.skip_binder().projection_ty.item_def_id
     }
 
+    /// Returns the `DefId` of the trait of the associated item being projected.
     #[inline]
-    pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        self.skip_binder().projection_ty.trait_def_id(tcx)
+    }
+
+    #[inline]
+    pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
+        self.map_bound(|predicate| predicate.projection_ty.self_ty())
+    }
+
+    /// Get the [PolyTraitRef] required for this projection to be well formed.
+    /// Note that for generic associated types the predicates of the associated
+    /// type also need to be checked.
+    #[inline]
+    pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
         // Note: unlike with `TraitRef::to_poly_trait_ref()`,
         // `self.0.trait_ref` is permitted to have escaping regions.
         // This is because here `self` has a `Binder` and so does our
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 388a5767870..754108ea3c5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -17,7 +17,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi;
 use std::borrow::Cow;
@@ -1112,20 +1112,35 @@ pub struct ProjectionTy<'tcx> {
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        tcx.associated_item(self.item_def_id).container.id()
+    }
+
+    /// Extracts the underlying trait reference and own substs from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+    pub fn trait_ref_and_own_substs(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let trait_generics = tcx.generics_of(def_id);
+        (
+            ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+            &self.substs[trait_generics.count()..],
+        )
+    }
+
     /// Extracts the underlying trait reference from this projection.
     /// For example, if this is a projection of `<T as Iterator>::Item`,
     /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the substs for generic associated types
+    /// consider calling [Self::trait_ref_and_own_substs] to get those
+    /// as well.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        // FIXME: This method probably shouldn't exist at all, since it's not
-        // clear what this method really intends to do. Be careful when
-        // using this method since the resulting TraitRef additionally
-        // contains the substs for the assoc_item, which strictly speaking
-        // is not correct
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
-        // Include substitutions for generic arguments of associated types
-        let assoc_item = tcx.associated_item(self.item_def_id);
-        let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
-        ty::TraitRef { def_id, substs: substs_assoc_item }
+        let def_id = self.trait_def_id(tcx);
+        ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 3233d1e048b..e9aaa652564 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
             }
             ty::PredicateKind::Projection(data) => {
-                let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.skip_binder().self_ty();
+                let self_ty = data.projection_ty.self_ty();
                 let ty = data.ty;
                 if predicate.references_error() {
                     return;
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 7d3589c4b6b..fdf5f697e61 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
-        let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+        let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
         chalk_solve::rust_ir::AliasEqBound {
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
-            parameters: self.projection_ty.substs[trait_ref.substs.len()..]
-                .iter()
-                .map(|arg| arg.lower_into(interner))
-                .collect(),
+            parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
             value: self.ty.lower_into(interner),
         }
     }
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index f34aaec10a9..431e6d70ff3 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
 
         // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur if there is a trait-reference
+        // infer the kind. This can occur when we elaborate a predicate
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
         let expected_kind = self
@@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!("deduce_sig_from_projection({:?})", projection);
 
-        let trait_ref = projection.to_poly_trait_ref(tcx);
+        let trait_def_id = projection.trait_def_id(tcx);
 
-        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
+        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
-        let is_gen = gen_trait == trait_ref.def_id();
+        let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
             return None;
@@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let input_tys = if is_fn {
-            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
             debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
@@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Check that this is a projection from the `Future` trait.
-        let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+        let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
         let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
-        if trait_ref.def_id != future_trait {
+        if trait_def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
             return None;
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index bc1a07801ae..75c73e0b67c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .filter_map(move |obligation| {
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
+                    ty::PredicateKind::Projection(data) => Some((
+                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
+                        obligation,
+                    )),
                     ty::PredicateKind::Trait(data, _) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d49c7cae822..14d019fa01a 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -24,6 +24,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::Obligation;
 
 use std::cmp::Ordering;
+use std::iter;
 
 use super::probe::Mode;
 use super::{CandidateSource, MethodError, NoMatchData};
@@ -649,21 +650,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ty::PredicateKind::Projection(pred) => {
                                 let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
-                                let trait_ref =
-                                    pred.skip_binder().projection_ty.trait_ref(self.tcx);
-                                let assoc = self
-                                    .tcx
-                                    .associated_item(pred.skip_binder().projection_ty.item_def_id);
-                                let ty = pred.skip_binder().ty;
-                                let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
-                                let quiet = format!(
-                                    "<_ as {}>::{} = {}",
-                                    trait_ref.print_only_trait_path(),
-                                    assoc.ident,
-                                    ty
+                                let projection_ty = pred.skip_binder().projection_ty;
+
+                                let substs_with_infer_self = tcx.mk_substs(
+                                    iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+                                        .chain(projection_ty.substs.iter().skip(1)),
                                 );
-                                bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
-                                Some((obligation, trait_ref.self_ty()))
+
+                                let quiet_projection_ty = ty::ProjectionTy {
+                                    substs: substs_with_infer_self,
+                                    item_def_id: projection_ty.item_def_id,
+                                };
+
+                                let ty = pred.skip_binder().ty;
+
+                                let obligation = format!("{} = {}", projection_ty, ty);
+                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+
+                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                                Some((obligation, projection_ty.self_ty()))
                             }
                             ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.trait_ref;
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
new file mode 100644
index 00000000000..36db3d1bb9e
--- /dev/null
+++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
@@ -0,0 +1,17 @@
+// Test that correct syntax is used in suggestion to constrain associated type
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<T>;
+}
+
+fn f<T: X>(a: T::Y<i32>) {
+    //~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+    //~| SUGGESTION Y<i32> = Vec<i32>>
+    let b: Vec<i32> = a;
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
new file mode 100644
index 00000000000..ecf559d9e94
--- /dev/null
+++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
@@ -0,0 +1,27 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/constraint-assoc-type-suggestion.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0308]: mismatched types
+  --> $DIR/constraint-assoc-type-suggestion.rs:13:23
+   |
+LL |     let b: Vec<i32> = a;
+   |            --------   ^ expected struct `Vec`, found associated type
+   |            |
+   |            expected due to this
+   |
+   = note:       expected struct `Vec<i32>`
+           found associated type `<T as X>::Y<i32>`
+help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+   |
+LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
+   |          ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
new file mode 100644
index 00000000000..2de4c7b8492
--- /dev/null
+++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
@@ -0,0 +1,35 @@
+// Test that the predicate printed in an unresolved method error prints the
+// generics for a generic associated type.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+//~| NOTE `#[warn(incomplete_features)]` on by default
+//~| NOTE see issue #44265
+
+trait X {
+    type Y<T>;
+}
+
+trait M {
+    fn f(&self) {}
+}
+
+impl<T: X<Y<i32> = i32>> M for T {}
+
+struct S;
+//~^ NOTE method `f` not found for this
+//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
+//~| NOTE doesn't satisfy `S: M`
+
+impl X for S {
+    type Y<T> = bool;
+}
+
+fn f(a: S) {
+    a.f();
+    //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
+    //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
+    //~| NOTE the following trait bounds were not satisfied:
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
new file mode 100644
index 00000000000..c94155d13c3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
@@ -0,0 +1,29 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
+   |
+LL | struct S;
+   | ---------
+   | |
+   | method `f` not found for this
+   | doesn't satisfy `<S as X>::Y<i32> = i32`
+   | doesn't satisfy `S: M`
+...
+LL |     a.f();
+   |       ^ method cannot be called on `S` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `<S as X>::Y<i32> = i32`
+           which is required by `S: M`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0599`.

From d785c8c447bd7f972e68e346a3f7b04c56ce486b Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:45:19 +0000
Subject: [PATCH 07/20] Remove unnecessary function parameters project.rs

---
 .../src/traits/project.rs                     | 30 ++++++-------------
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a38e3817a95..bfaca4215ed 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>(
         return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
     }
 
-    let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
-
-    debug!(?obligation_trait_ref);
-
-    if obligation_trait_ref.references_error() {
+    if obligation.predicate.references_error() {
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
     }
 
@@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>(
     // Make sure that the following procedures are kept in order. ParamEnv
     // needs to be first because it has highest priority, and Select checks
     // the return value of push_candidate which assumes it's ran at last.
-    assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
 
     if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
         // Avoid normalization cycle from selection (see
         // `assemble_candidates_from_object_ty`).
         // FIXME(lazy_normalization): Lazy normalization should save us from
-        // having to do special case this.
+        // having to special case this.
     } else {
-        assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+        assemble_candidates_from_impls(selcx, obligation, &mut candidates);
     };
 
     match candidates {
@@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>(
 fn assemble_candidates_from_param_env<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_param_env(..)");
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::ParamEnv,
         obligation.param_env.caller_bounds().iter(),
@@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
 fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_trait_def(..)");
@@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let bounds = match *obligation_trait_ref.self_ty().kind() {
+    let bounds = match *obligation.predicate.self_ty().kind() {
         ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
         ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
@@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::TraitDef,
         bounds.iter(),
@@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_object_ty(..)");
 
     let tcx = selcx.tcx();
 
-    let self_ty = obligation_trait_ref.self_ty();
+    let self_ty = obligation.predicate.self_ty();
     let object_ty = selcx.infcx().shallow_resolve(self_ty);
     let data = match object_ty.kind() {
         ty::Dynamic(data, ..) => data,
@@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::Object,
         env_predicates,
@@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
@@ -947,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_impls");
 
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
-    let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
+    let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
     let _ = selcx.infcx().commit_if_ok(|_| {
         let impl_source = match selcx.select(&trait_obligation) {

From eeb82e45fe42ec77efd99b706f96b3e66bcfb524 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Fri, 12 Feb 2021 22:45:54 +0000
Subject: [PATCH 08/20] Add more tests for generic associated type bounds

---
 .../generic-associated-type-bounds.rs         | 35 +++++++++++++
 .../generic-associated-types/issue-76535.rs   |  6 +--
 .../issue-76535.stderr                        | 39 +--------------
 .../generic-associated-types/issue-79422.rs   |  5 +-
 .../issue-79422.stderr                        | 40 +++------------
 .../projection-type-lifetime-mismatch.rs      | 36 +++++++++++++
 .../projection-type-lifetime-mismatch.stderr  | 27 ++++++++++
 .../unsatified-item-lifetime-bound.rs         | 28 +++++++++++
 .../unsatified-item-lifetime-bound.stderr     | 50 +++++++++++++++++++
 9 files changed, 190 insertions(+), 76 deletions(-)
 create mode 100644 src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
 create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
 create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
 create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs
 create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr

diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
new file mode 100644
index 00000000000..8094450e5e1
--- /dev/null
+++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs
@@ -0,0 +1,35 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a>;
+    fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+
+    fn m(&self) -> Self::Y<'_> {
+        self
+    }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &() {
+    x.m()
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &() {
+    x.m()
+}
+
+fn h(x: &()) -> &() {
+    x.m()
+}
+
+fn main() {
+    f(&());
+    g(&());
+    h(&());
+}
diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs
index 2b4757d8d15..5e73a882986 100644
--- a/src/test/ui/generic-associated-types/issue-76535.rs
+++ b/src/test/ui/generic-associated-types/issue-76535.rs
@@ -1,11 +1,11 @@
 #![feature(generic_associated_types)]
- //~^ WARNING the feature
+//~^ WARNING the feature
 
 pub trait SubTrait {}
 
 pub trait SuperTrait {
     type SubType<'a>: SubTrait;
-      //~^ ERROR missing generics for associated
+    //~^ ERROR missing generics for associated
 
     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
 }
@@ -36,6 +36,4 @@ impl SuperTrait for SuperStruct {
 
 fn main() {
     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-      //~^ ERROR the trait
-      //~| ERROR the trait
 }
diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr
index ce4875af9c0..17661e0d90a 100644
--- a/src/test/ui/generic-associated-types/issue-76535.stderr
+++ b/src/test/ui/generic-associated-types/issue-76535.stderr
@@ -23,41 +23,6 @@ help: use angle brackets to add missing lifetime argument
 LL |     type SubType<'a><'a>: SubTrait;
    |                 ^^^^
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
-  --> $DIR/issue-76535.rs:38:14
-   |
-LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
-   |
-   = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-76535.rs:10:37
-   |
-LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
-...
-LL |     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
-   |                                     ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
+error: aborting due to previous error; 1 warning emitted
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
-  --> $DIR/issue-76535.rs:38:57
-   |
-LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
-   |
-   = help: consider moving `get_sub` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-76535.rs:10:37
-   |
-LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
-...
-LL |     fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
-   |                                     ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
-   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
-   = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
-
-error: aborting due to 3 previous errors; 1 warning emitted
-
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs
index 26b38430dd9..aeb33ca5464 100644
--- a/src/test/ui/generic-associated-types/issue-79422.rs
+++ b/src/test/ui/generic-associated-types/issue-79422.rs
@@ -19,7 +19,7 @@ impl<'a, T> RefCont<'a, T> for Box<T> {
 
 trait MapLike<K, V> {
     type VRefCont<'a>: RefCont<'a, V>;
-      //~^ ERROR missing generics
+    //~^ ERROR missing generics
     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
 }
 
@@ -42,6 +42,5 @@ impl<K, V: Default> MapLike<K, V> for Source {
 fn main() {
     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-      //~^ ERROR the trait
-      //~^^^ ERROR the trait
+    //~^^ ERROR type mismatch resolving
 }
diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr
index d2e12962715..a119bff03e2 100644
--- a/src/test/ui/generic-associated-types/issue-79422.stderr
+++ b/src/test/ui/generic-associated-types/issue-79422.stderr
@@ -14,41 +14,17 @@ help: use angle brackets to add missing lifetime argument
 LL |     type VRefCont<'a><'a>: RefCont<'a, V>;
    |                  ^^^^
 
-error[E0038]: the trait `MapLike` cannot be made into an object
-  --> $DIR/issue-79422.rs:44:12
-   |
-LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
-   |
-   = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-79422.rs:23:38
-   |
-LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
-...
-LL |     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
-
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
   --> $DIR/issue-79422.rs:43:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
    |
-   = help: consider moving `get` to another trait
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/issue-79422.rs:23:38
-   |
-LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
-...
-LL |     fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
-   = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
-   = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
+   = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
+                 found reference `&'static u8`
+   = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0038, E0107.
-For more information about an error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0107, E0271.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
new file mode 100644
index 00000000000..0024e127a98
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
@@ -0,0 +1,36 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a>;
+    fn m(&self) -> Self::Y<'_>;
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+
+    fn m(&self) -> Self::Y<'_> {
+        self
+    }
+}
+
+fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn h(x: &()) -> &'static () {
+    x.m()
+    //~^ ERROR explicit lifetime required
+}
+
+fn main() {
+    f(&());
+    g(&());
+    h(&());
+}
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
new file mode 100644
index 00000000000..13b765dfa57
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
@@ -0,0 +1,27 @@
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:18:5
+   |
+LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
+   |         ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X<Y<'a> = &'a ()>`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:23:5
+   |
+LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
+   |                                       -- help: add explicit lifetime `'static` to the type of `x`: `&'static T`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/projection-type-lifetime-mismatch.rs:28:5
+   |
+LL | fn h(x: &()) -> &'static () {
+   |         --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()`
+LL |     x.m()
+   |     ^^^^^ lifetime `'static` required
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs
new file mode 100644
index 00000000000..7bcc7ba752a
--- /dev/null
+++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs
@@ -0,0 +1,28 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+pub trait X {
+    type Y<'a: 'static>;
+    //~^ WARNING unnecessary lifetime parameter
+}
+
+impl X for () {
+    type Y<'a> = &'a ();
+}
+
+struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+    f: <T as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+struct C<'a, T: X> {
+    f: <T as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+struct D<'a> {
+    f: <() as X>::Y<'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
new file mode 100644
index 00000000000..1c81d33ccfe
--- /dev/null
+++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
@@ -0,0 +1,50 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/unsatified-item-lifetime-bound.rs:5:12
+   |
+LL |     type Y<'a: 'static>;
+   |            ^^^^^^^^^^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:14:8
+   |
+LL |     f: <T as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:13:10
+   |
+LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:19:8
+   |
+LL |     f: <T as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:18:10
+   |
+LL | struct C<'a, T: X> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatified-item-lifetime-bound.rs:24:8
+   |
+LL |     f: <() as X>::Y<'a>,
+   |        ^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10
+  --> $DIR/unsatified-item-lifetime-bound.rs:23:10
+   |
+LL | struct D<'a> {
+   |          ^^
+   = note: but lifetime parameter must outlive the static lifetime
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0478`.

From 7e368e57f278b8073193c73001f4efc4af08fdfd Mon Sep 17 00:00:00 2001
From: Ellen <supbscripter@gmail.com>
Date: Mon, 15 Feb 2021 11:38:20 +0000
Subject: [PATCH 09/20] the environment round here is awfully empty

capitalism
---
 .../src/traits/const_evaluatable.rs           | 13 +++++-----
 .../error_reporting/on_unimplemented.rs       | 25 +++++++------------
 .../dont-evaluate-array-len-on-err-1.rs       | 22 ++++++++++++++++
 .../dont-evaluate-array-len-on-err-1.stderr   | 12 +++++++++
 4 files changed, 49 insertions(+), 23 deletions(-)
 create mode 100644 src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
 create mode 100644 src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr

diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index b1ac02d9fed..8a1be7ea172 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -72,17 +72,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                 // We were unable to unify the abstract constant with
                 // a constant found in the caller bounds, there are
                 // now three possible cases here.
-                //
-                // - The substs are concrete enough that we can simply
-                //   try and evaluate the given constant.
-                // - The abstract const still references an inference
-                //   variable, in this case we return `TooGeneric`.
-                // - The abstract const references a generic parameter,
-                //   this means that we emit an error here.
                 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
                 enum FailureKind {
+                    /// The abstract const still references an inference
+                    /// variable, in this case we return `TooGeneric`.
                     MentionsInfer,
+                    /// The abstract const references a generic parameter,
+                    /// this means that we emit an error here.
                     MentionsParam,
+                    /// The substs are concrete enough that we can simply
+                    /// try and evaluate the given constant.
                     Concrete,
                 }
                 let mut failure_kind = FailureKind::Concrete;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 69f66f6e6b1..e6a1cf58fe3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -200,22 +200,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(def) = aty.ty_adt_def() {
                 // We also want to be able to select the array's type's original
                 // signature with no type arguments resolved
-                flags.push((
-                    sym::_Self,
-                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
-                ));
-                let tcx = self.tcx;
-                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
-                    ));
-                } else {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
-                    ));
-                }
+                let type_string = self.tcx.type_of(def.did).to_string();
+                flags.push((sym::_Self, Some(format!("[{}]", type_string))));
+
+                let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                let string = match len {
+                    Some(n) => format!("[{}; {}]", type_string, n),
+                    None => format!("[{}; _]", type_string),
+                };
+                flags.push((sym::_Self, Some(string)));
             }
         }
         if let ty::Dynamic(traits, _) = self_ty.kind() {
diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
new file mode 100644
index 00000000000..afef748ff46
--- /dev/null
+++ b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
@@ -0,0 +1,22 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that during error handling for the "trait not implemented" error
+// we dont try to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
+
+struct Adt;
+
+trait Foo {
+    type Assoc;
+    fn foo()
+    where
+        [Adt; std::mem::size_of::<Self::Assoc>()]: ,
+    {
+        <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+        //~^ Error: the trait bound
+    }
+
+    fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
new file mode 100644
index 00000000000..d894fa90ba9
--- /dev/null
+++ b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied
+  --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9
+   |
+LL |         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]`
+...
+LL |     fn bar() {}
+   |     -------- required by `Foo::bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.

From 0f04875d2e21919e5f716b9946407ba07de08840 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Wed, 17 Feb 2021 19:26:38 +0900
Subject: [PATCH 10/20] replace if-let and while-let with `if let` and `while
 let`

---
 .../rustc_error_codes/src/error_codes/E0162.md   |  2 +-
 .../rustc_error_codes/src/error_codes/E0165.md   |  2 +-
 compiler/rustc_lint_defs/src/builtin.rs          | 10 +++++-----
 .../src/thir/pattern/check_match.rs              |  6 +++---
 compiler/rustc_passes/src/check_const.rs         |  2 +-
 src/test/ui/binding/if-let.rs                    |  4 ++--
 .../closure-origin-single-variant-diagnostics.rs |  2 +-
 ...sure-origin-single-variant-diagnostics.stderr |  2 +-
 src/test/ui/expr/if/if-let.rs                    | 16 ++++++++--------
 src/test/ui/expr/if/if-let.stderr                | 16 ++++++++--------
 src/test/ui/issues/issue-19991.rs                |  2 +-
 .../usefulness/deny-irrefutable-let-patterns.rs  |  4 ++--
 .../deny-irrefutable-let-patterns.stderr         |  4 ++--
 src/test/ui/rfc-2294-if-let-guard/warns.rs       |  2 +-
 src/test/ui/rfc-2294-if-let-guard/warns.stderr   |  2 +-
 src/test/ui/while-let.rs                         |  6 +++---
 src/test/ui/while-let.stderr                     |  6 +++---
 src/tools/clippy/clippy_lints/src/loops.rs       |  2 +-
 18 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0162.md b/compiler/rustc_error_codes/src/error_codes/E0162.md
index 98146147f39..0161c9325c2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0162.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0162.md
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-An if-let pattern attempts to match the pattern, and enters the body if the
+An `if let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding instead. For instance:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0165.md b/compiler/rustc_error_codes/src/error_codes/E0165.md
index 92243db4550..7bcd6c0cbf3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0165.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0165.md
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-A while-let pattern attempts to match the pattern, and enters the body if the
+A `while let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding inside a `loop` instead. For instance:
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index f0a5ea150b7..8eeee19cc29 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1815,7 +1815,7 @@ declare_lint! {
 
 declare_lint! {
     /// The `irrefutable_let_patterns` lint detects detects [irrefutable
-    /// patterns] in [if-let] and [while-let] statements.
+    /// patterns] in [`if let`] and [`while let`] statements.
     ///
     ///
     ///
@@ -1832,7 +1832,7 @@ declare_lint! {
     /// ### Explanation
     ///
     /// There usually isn't a reason to have an irrefutable pattern in an
-    /// if-let or while-let statement, because the pattern will always match
+    /// `if let` or `while let` statement, because the pattern will always match
     /// successfully. A [`let`] or [`loop`] statement will suffice. However,
     /// when generating code with a macro, forbidding irrefutable patterns
     /// would require awkward workarounds in situations where the macro
@@ -1843,14 +1843,14 @@ declare_lint! {
     /// See [RFC 2086] for more details.
     ///
     /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
-    /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
-    /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+    /// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+    /// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
     /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
     /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
     /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
     pub IRREFUTABLE_LET_PATTERNS,
     Warn,
-    "detects irrefutable patterns in if-let and while-let statements"
+    "detects irrefutable patterns in `if let` and `while let` statements"
 }
 
 declare_lint! {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 6ec602ff59b..e928f3c5d4d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -368,9 +368,9 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
     tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
         let msg = match source {
-            hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
-            hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
-            hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
+            hir::MatchSource::IfLetDesugar { .. } => "irrefutable `if let` pattern",
+            hir::MatchSource::WhileLetDesugar => "irrefutable `while let` pattern",
+            hir::MatchSource::IfLetGuardDesugar => "irrefutable `if let` guard",
             _ => bug!(),
         };
         lint.build(msg).emit()
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8950f9b33b6..9328f7cd9ec 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -45,7 +45,7 @@ impl NonConstExpr {
                 return None;
             }
 
-            Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
+            Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
 
             // All other expressions are allowed.
             Self::Loop(Loop | While | WhileLet)
diff --git a/src/test/ui/binding/if-let.rs b/src/test/ui/binding/if-let.rs
index 3ea8d402a3e..28d57e92c37 100644
--- a/src/test/ui/binding/if-let.rs
+++ b/src/test/ui/binding/if-let.rs
@@ -6,7 +6,7 @@ pub fn main() {
     if let Some(y) = x {
         assert_eq!(y, 3);
     } else {
-        panic!("if-let panicked");
+        panic!("`if let` panicked");
     }
     let mut worked = false;
     if let Some(_) = x {
@@ -54,7 +54,7 @@ pub fn main() {
         if let Foo::Two(b) = a {
             assert_eq!(b, 42_usize);
         } else {
-            panic!("panic in nested if-let");
+            panic!("panic in nested `if let`");
         }
     }
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
index 8486f03f2eb..6107a082237 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
@@ -16,7 +16,7 @@ fn main() {
         // FIXME(project-rfc-2229#24): Change this to be a destructure pattern
         // once this is fixed, to remove the warning.
         if let SingleVariant::Point(ref mut x, _) = point {
-            //~^ WARNING: irrefutable if-let pattern
+            //~^ WARNING: irrefutable `if let` pattern
             *x += 1;
         }
     };
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
index ad66f6d7ffc..5c7a56c7ced 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
@@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
    |
 LL | /         if let SingleVariant::Point(ref mut x, _) = point {
diff --git a/src/test/ui/expr/if/if-let.rs b/src/test/ui/expr/if/if-let.rs
index 2ab0f9fed3f..7208e388a16 100644
--- a/src/test/ui/expr/if/if-let.rs
+++ b/src/test/ui/expr/if/if-let.rs
@@ -4,8 +4,8 @@ fn macros() {
     macro_rules! foo{
         ($p:pat, $e:expr, $b:block) => {{
             if let $p = $e $b
-            //~^ WARN irrefutable if-let
-            //~| WARN irrefutable if-let
+            //~^ WARN irrefutable `if let`
+            //~| WARN irrefutable `if let`
         }}
     }
     macro_rules! bar{
@@ -23,27 +23,27 @@ fn macros() {
 }
 
 pub fn main() {
-    if let a = 1 { //~ WARN irrefutable if-let
+    if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 
-    if let a = 1 { //~ WARN irrefutable if-let
+    if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     } else if true {
-        println!("else-if in irrefutable if-let");
+        println!("else-if in irrefutable `if let`");
     } else {
-        println!("else in irrefutable if-let");
+        println!("else in irrefutable `if let`");
     }
 
     if let 1 = 2 {
         println!("refutable pattern");
-    } else if let a = 1 { //~ WARN irrefutable if-let
+    } else if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 
     if true {
         println!("if");
-    } else if let a = 1 { //~ WARN irrefutable if-let
+    } else if let a = 1 { //~ WARN irrefutable `if let`
         println!("irrefutable pattern");
     }
 }
diff --git a/src/test/ui/expr/if/if-let.stderr b/src/test/ui/expr/if/if-let.stderr
index ee2b78af3b8..468e913a773 100644
--- a/src/test/ui/expr/if/if-let.stderr
+++ b/src/test/ui/expr/if/if-let.stderr
@@ -1,4 +1,4 @@
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:6:13
    |
 LL |               if let $p = $e $b
@@ -12,7 +12,7 @@ LL | |     });
    = note: `#[warn(irrefutable_let_patterns)]` on by default
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:6:13
    |
 LL |               if let $p = $e $b
@@ -25,7 +25,7 @@ LL | |     });
    |
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:26:5
    |
 LL | /     if let a = 1 {
@@ -33,19 +33,19 @@ LL | |         println!("irrefutable pattern");
 LL | |     }
    | |_____^
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:30:5
    |
 LL | /     if let a = 1 {
 LL | |         println!("irrefutable pattern");
 LL | |     } else if true {
-LL | |         println!("else-if in irrefutable if-let");
+LL | |         println!("else-if in irrefutable `if let`");
 LL | |     } else {
-LL | |         println!("else in irrefutable if-let");
+LL | |         println!("else in irrefutable `if let`");
 LL | |     }
    | |_____^
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:40:12
    |
 LL |       } else if let a = 1 {
@@ -54,7 +54,7 @@ LL | |         println!("irrefutable pattern");
 LL | |     }
    | |_____^
 
-warning: irrefutable if-let pattern
+warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:46:12
    |
 LL |       } else if let a = 1 {
diff --git a/src/test/ui/issues/issue-19991.rs b/src/test/ui/issues/issue-19991.rs
index 0f3f83001d3..1f3b73f96d8 100644
--- a/src/test/ui/issues/issue-19991.rs
+++ b/src/test/ui/issues/issue-19991.rs
@@ -1,4 +1,4 @@
-// Test if the sugared if-let construct correctly prints "missing an else clause" when an else
+// Test if the sugared `if let` construct correctly prints "missing an else clause" when an else
 // clause does not exist, instead of the unsympathetic "`match` arms have incompatible types"
 
 fn main() {
diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
index 14040c8ada6..c1cfa4695c9 100644
--- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
+++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs
@@ -1,9 +1,9 @@
 #![deny(irrefutable_let_patterns)]
 
 fn main() {
-    if let _ = 5 {} //~ ERROR irrefutable if-let pattern
+    if let _ = 5 {} //~ ERROR irrefutable `if let` pattern
 
-    while let _ = 5 { //~ ERROR irrefutable while-let pattern
+    while let _ = 5 { //~ ERROR irrefutable `while let` pattern
         break;
     }
 }
diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
index 308a6c7c58e..1de30f7db06 100644
--- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr
@@ -1,4 +1,4 @@
-error: irrefutable if-let pattern
+error: irrefutable `if let` pattern
   --> $DIR/deny-irrefutable-let-patterns.rs:4:5
    |
 LL |     if let _ = 5 {}
@@ -10,7 +10,7 @@ note: the lint level is defined here
 LL | #![deny(irrefutable_let_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: irrefutable while-let pattern
+error: irrefutable `while let` pattern
   --> $DIR/deny-irrefutable-let-patterns.rs:6:5
    |
 LL | /     while let _ = 5 {
diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.rs b/src/test/ui/rfc-2294-if-let-guard/warns.rs
index 9691a12f45b..d921367b917 100644
--- a/src/test/ui/rfc-2294-if-let-guard/warns.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/warns.rs
@@ -5,7 +5,7 @@
 fn irrefutable_let_guard() {
     match Some(()) {
         Some(x) if let () = x => {}
-        //~^ ERROR irrefutable if-let guard
+        //~^ ERROR irrefutable `if let` guard
         _ => {}
     }
 }
diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr
index 45720f9fbc5..33fa25d32fb 100644
--- a/src/test/ui/rfc-2294-if-let-guard/warns.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr
@@ -1,4 +1,4 @@
-error: irrefutable if-let guard
+error: irrefutable `if let` guard
   --> $DIR/warns.rs:7:24
    |
 LL |         Some(x) if let () = x => {}
diff --git a/src/test/ui/while-let.rs b/src/test/ui/while-let.rs
index cfbf7565cb6..b9a49b47c8f 100644
--- a/src/test/ui/while-let.rs
+++ b/src/test/ui/while-let.rs
@@ -5,8 +5,8 @@ fn macros() {
     macro_rules! foo{
         ($p:pat, $e:expr, $b:block) => {{
             while let $p = $e $b
-            //~^ WARN irrefutable while-let
-            //~| WARN irrefutable while-let
+            //~^ WARN irrefutable `while let`
+            //~| WARN irrefutable `while let`
         }}
     }
     macro_rules! bar{
@@ -24,7 +24,7 @@ fn macros() {
 }
 
 pub fn main() {
-    while let _a = 1 { //~ WARN irrefutable while-let
+    while let _a = 1 { //~ WARN irrefutable `while let`
         println!("irrefutable pattern");
         break;
     }
diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr
index 867c95c0e02..6538b9fbe6f 100644
--- a/src/test/ui/while-let.stderr
+++ b/src/test/ui/while-let.stderr
@@ -1,4 +1,4 @@
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
@@ -12,7 +12,7 @@ LL | |     });
    = note: `#[warn(irrefutable_let_patterns)]` on by default
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:7:13
    |
 LL |               while let $p = $e $b
@@ -25,7 +25,7 @@ LL | |     });
    |
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: irrefutable while-let pattern
+warning: irrefutable `while let` pattern
   --> $DIR/while-let.rs:27:5
    |
 LL | /     while let _a = 1 {
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 5211ca7da32..eb0047602fd 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -341,7 +341,7 @@ declare_clippy_lint! {
     /// ```
     pub WHILE_LET_ON_ITERATOR,
     style,
-    "using a while-let loop instead of a for loop on an iterator"
+    "using a `while let` loop instead of a for loop on an iterator"
 }
 
 declare_clippy_lint! {

From 43aed7441ee289c6228ecead91ee66245122b880 Mon Sep 17 00:00:00 2001
From: hyd-dev <yd-huang@outlook.com>
Date: Sat, 30 Jan 2021 00:23:56 +0800
Subject: [PATCH 11/20] [libtest] Run the test synchronously when hitting
 thread limit

---
 library/test/src/lib.rs                         | 13 ++++++++++++-
 src/test/run-make/libtest-thread-limit/Makefile |  7 +++++++
 src/test/run-make/libtest-thread-limit/test.rs  | 16 ++++++++++++++++
 3 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 src/test/run-make/libtest-thread-limit/Makefile
 create mode 100644 src/test/run-make/libtest-thread-limit/test.rs

diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 3ff79eaea49..50b71cb561f 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -506,7 +506,18 @@ pub fn run_test(
         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
         if concurrency == Concurrent::Yes && supports_threads {
             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
-            Some(cfg.spawn(runtest).unwrap())
+            let mut runtest = Arc::new(Mutex::new(Some(runtest)));
+            let runtest2 = runtest.clone();
+            match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) {
+                Ok(handle) => Some(handle),
+                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+                    // `ErrorKind::WouldBlock` means hitting the thread limit on some
+                    // platforms, so run the test synchronously here instead.
+                    Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
+                    None
+                }
+                Err(e) => panic!("failed to spawn thread to run test: {}", e),
+            }
         } else {
             runtest();
             None
diff --git a/src/test/run-make/libtest-thread-limit/Makefile b/src/test/run-make/libtest-thread-limit/Makefile
new file mode 100644
index 00000000000..29c1bc71d87
--- /dev/null
+++ b/src/test/run-make/libtest-thread-limit/Makefile
@@ -0,0 +1,7 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-linux
+
+all:
+	$(RUSTC) test.rs --test --target $(TARGET)
+	$(shell ulimit -p 0 && $(call RUN,test))
diff --git a/src/test/run-make/libtest-thread-limit/test.rs b/src/test/run-make/libtest-thread-limit/test.rs
new file mode 100644
index 00000000000..d899411a49e
--- /dev/null
+++ b/src/test/run-make/libtest-thread-limit/test.rs
@@ -0,0 +1,16 @@
+#![feature(once_cell)]
+
+use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
+
+static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
+
+#[test]
+fn spawn_thread_would_block() {
+    assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock);
+    THREAD_ID.set(thread::current().id()).unwrap();
+}
+
+#[test]
+fn run_in_same_thread() {
+    assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id());
+}

From 2a66685ebfdcd58a3c3fff0caeff6b13774543f5 Mon Sep 17 00:00:00 2001
From: Ryan Levick <me@ryanlevick.com>
Date: Wed, 17 Feb 2021 15:07:36 +0100
Subject: [PATCH 12/20] Make sure pdbs are copied along with exe and dlls when
 bootstrapping

---
 src/bootstrap/compile.rs | 6 ++++--
 src/bootstrap/util.rs    | 6 ++++++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index dee0c154201..7d5e3d05b11 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -27,7 +27,7 @@ use crate::config::TargetSelection;
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
-use crate::util::{exe, is_dylib, symlink_dir};
+use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
 use crate::{Compiler, DependencyType, GitRepo, Mode};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
@@ -1049,7 +1049,8 @@ impl Step for Assemble {
         let src_libdir = builder.sysroot_libdir(build_compiler, host);
         for f in builder.read_dir(&src_libdir) {
             let filename = f.file_name().into_string().unwrap();
-            if is_dylib(&filename) && !proc_macros.contains(&filename) {
+            if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
+            {
                 builder.copy(&f.path(), &rustc_libdir.join(&filename));
             }
         }
@@ -1166,6 +1167,7 @@ pub fn run_cargo(
             if !(filename.ends_with(".rlib")
                 || filename.ends_with(".lib")
                 || filename.ends_with(".a")
+                || is_debug_info(&filename)
                 || is_dylib(&filename)
                 || (is_check && filename.ends_with(".rmeta")))
             {
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index b35d1b99fa5..b4421a82714 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -32,6 +32,12 @@ pub fn is_dylib(name: &str) -> bool {
     name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
 }
 
+/// Returns `true` if the file name given looks like a debug info file
+pub fn is_debug_info(name: &str) -> bool {
+    // FIXME: consider split debug info on other platforms (e.g., Linux, macOS)
+    name.ends_with(".pdb")
+}
+
 /// Returns the corresponding relative library directory that the compiler's
 /// dylibs will be found in.
 pub fn libdir(target: TargetSelection) -> &'static str {

From 32c97da0f466ceff1512d62729c246a8e3951afe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 16 Feb 2021 11:02:39 -0800
Subject: [PATCH 13/20] In some limited cases, suggest `where` bounds for
 non-type params

Partially address #81971.
---
 compiler/rustc_middle/src/ty/diagnostics.rs   | 30 +++++++++++++++++++
 .../src/traits/error_reporting/suggestions.rs | 26 ++++++++++++++--
 src/test/ui/partialeq_help.stderr             |  4 +++
 .../deafult-associated-type-bound-2.stderr    |  4 +++
 src/test/ui/suggestions/suggest-change-mut.rs |  2 +-
 .../ui/suggestions/suggest-change-mut.stderr  |  4 +++
 .../ui/traits/suggest-where-clause.stderr     |  8 +++++
 7 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 3b7dc25b6cf..f41bb7e6d63 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -75,6 +75,36 @@ impl<'tcx> TyS<'tcx> {
     }
 }
 
+pub fn suggest_arbitrary_trait_bound(
+    generics: &hir::Generics<'_>,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    constraint: &str,
+) -> bool {
+    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+    match (param, param_name) {
+        (Some(_), "Self") => return false,
+        _ => {}
+    }
+    // Suggest a where clause bound for a non-type paremeter.
+    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
+        ("introducing a", " where ")
+    } else {
+        ("extending the", ", ")
+    };
+    err.span_suggestion_verbose(
+        generics.where_clause.tail_span_for_suggestion(),
+        &format!(
+            "consider {} `where` bound, but there might be an alternative better way to express \
+             this requirement",
+            action,
+        ),
+        format!("{}{}: {}", prefix, param_name, constraint),
+        Applicability::MaybeIncorrect,
+    );
+    true
+}
+
 /// Suggest restricting a type param with a new bound.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 9fd2f121007..5c97791530d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -17,8 +17,8 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::{
-    self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
-    TyCtxt, TypeFoldable, WithConstness,
+    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -334,7 +334,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
             ty::Projection(projection) => (false, Some(projection)),
-            _ => return,
+            _ => (false, None),
         };
 
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
@@ -453,6 +453,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 }
 
+                hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Struct(_, generics)
+                        | hir::ItemKind::Enum(_, generics)
+                        | hir::ItemKind::Union(_, generics)
+                        | hir::ItemKind::Trait(_, _, generics, ..)
+                        | hir::ItemKind::Impl(hir::Impl { generics, .. })
+                        | hir::ItemKind::Fn(_, generics, _)
+                        | hir::ItemKind::TyAlias(_, generics)
+                        | hir::ItemKind::TraitAlias(generics, _)
+                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                    ..
+                }) if !param_ty => {
+                    // Missing generic type parameter bound.
+                    let param_name = self_ty.to_string();
+                    let constraint = trait_ref.print_only_trait_path().to_string();
+                    if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
+                        return;
+                    }
+                }
                 hir::Node::Crate(..) => return,
 
                 _ => {}
diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr
index 6decbef1af4..e14e17c1622 100644
--- a/src/test/ui/partialeq_help.stderr
+++ b/src/test/ui/partialeq_help.stderr
@@ -5,6 +5,10 @@ LL |     a == b;
    |       ^^ no implementation for `&T == T`
    |
    = help: the trait `PartialEq<T>` is not implemented for `&T`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
index 2bc14dbe3b2..0e8a774bce3 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
+++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
@@ -18,6 +18,10 @@ LL |     default type U = &'static B;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
    |
    = help: the trait `PartialEq<B>` is not implemented for `&'static B`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/suggestions/suggest-change-mut.rs b/src/test/ui/suggestions/suggest-change-mut.rs
index 8b465aae66b..a2bc6fd09b5 100644
--- a/src/test/ui/suggestions/suggest-change-mut.rs
+++ b/src/test/ui/suggestions/suggest-change-mut.rs
@@ -2,7 +2,7 @@
 
 use std::io::{BufRead, BufReader, Read, Write};
 
-fn issue_81421<T: Read + Write>(mut stream: T) {
+fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound
     let initial_message = format!("Hello world");
     let mut buffer: Vec<u8> = Vec::new();
     let bytes_written = stream.write_all(initial_message.as_bytes());
diff --git a/src/test/ui/suggestions/suggest-change-mut.stderr b/src/test/ui/suggestions/suggest-change-mut.stderr
index cb156f7c787..9b8181647a0 100644
--- a/src/test/ui/suggestions/suggest-change-mut.stderr
+++ b/src/test/ui/suggestions/suggest-change-mut.stderr
@@ -9,6 +9,10 @@ help: consider removing the leading `&`-reference
    |
 LL |         let mut stream_reader = BufReader::new(stream);
    |                                               --
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read {
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^
 help: consider changing this borrow's mutability
    |
 LL |         let mut stream_reader = BufReader::new(&mut stream);
diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr
index b50017afa4d..86d589ffa9e 100644
--- a/src/test/ui/traits/suggest-where-clause.stderr
+++ b/src/test/ui/traits/suggest-where-clause.stderr
@@ -35,6 +35,10 @@ LL |     <u64 as From<T>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
    |
    = note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> {
+   |                                    ^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfied
   --> $DIR/suggest-where-clause.rs:18:5
@@ -43,6 +47,10 @@ LL |     <u64 as From<<T as Iterator>::Item>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
    |
    = note: required by `from`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied
   --> $DIR/suggest-where-clause.rs:23:5

From ec50a2086a7263b24795f70cfefb3a83737599f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Wed, 17 Feb 2021 20:37:09 +0100
Subject: [PATCH 14/20] avoid converting types into themselves
 (clippy::useless_conversion)

---
 compiler/rustc_parse/src/parser/expr.rs  | 2 +-
 compiler/rustc_parse/src/parser/stmt.rs  | 6 +++---
 compiler/rustc_typeck/src/astconv/mod.rs | 1 -
 src/bootstrap/install.rs                 | 2 +-
 src/librustdoc/core.rs                   | 2 +-
 src/librustdoc/json/conversions.rs       | 2 +-
 6 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 20430ece05b..20398d3321d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -513,7 +513,7 @@ impl<'a> Parser<'a> {
             token::Ident(..) if this.is_mistaken_not_ident_negation() => {
                 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
             }
-            _ => return this.parse_dot_or_call_expr(Some(attrs.into())),
+            _ => return this.parse_dot_or_call_expr(Some(attrs)),
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index e36ebd5e481..9a236925eff 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -97,7 +97,7 @@ impl<'a> Parser<'a> {
             self.mk_stmt(lo, StmtKind::Empty)
         } else if self.token != token::CloseDelim(token::Brace) {
             // Remainder are line-expr stmts.
-            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
             self.error_outer_attrs(&attrs.take_for_recovery());
@@ -131,7 +131,7 @@ impl<'a> Parser<'a> {
             };
 
             let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
                 this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
             })?;
             Ok((
@@ -213,7 +213,7 @@ impl<'a> Parser<'a> {
     }
 
     fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs.into())?;
+        let local = self.parse_local(attrs)?;
         Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
     }
 
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2e1fb44d3b5..a132cda6fef 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1473,7 +1473,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }),
                     assoc_name,
                 )
-                .into_iter()
             },
             || param_name.to_string(),
             assoc_name,
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 22124ec67f5..b427420d577 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -53,7 +53,7 @@ fn install_sh(
 }
 
 fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
-    PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)))
+    config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
 }
 
 fn prepare_dir(mut path: PathBuf) -> String {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index d79c47bbe3d..e20c84ba053 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -161,7 +161,7 @@ impl<'tcx> DocContext<'tcx> {
             }
             Entry::Occupied(e) => e.into_mut(),
         };
-        *def_index = DefIndex::from(*def_index + 1);
+        *def_index = *def_index + 1;
 
         DefId { krate: crate_num, index: *def_index }
     }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index e2652ca378a..b248fcdefbe 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -182,7 +182,7 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>) -> ItemEnum {
             bounds: g.into_iter().map(Into::into).collect(),
             default: t.map(Into::into),
         },
-        StrippedItem(inner) => from_clean_item_kind(*inner, tcx).into(),
+        StrippedItem(inner) => from_clean_item_kind(*inner, tcx),
         PrimitiveItem(_) | KeywordItem(_) => {
             panic!("{:?} is not supported for JSON output", item)
         }

From 5ae392f3c6786d6aba065bcf94baedf5017a66c3 Mon Sep 17 00:00:00 2001
From: Jesus Rubio <jesusprubio@gmail.com>
Date: Thu, 18 Feb 2021 06:53:01 +0100
Subject: [PATCH 15/20] Add long explanation for E0549

---
 compiler/rustc_error_codes/src/error_codes.rs |  4 +-
 .../src/error_codes/E0549.md                  | 37 +++++++++++++++++++
 .../stability-attribute-sanity.stderr         |  2 +-
 3 files changed, 39 insertions(+), 4 deletions(-)
 create mode 100644 compiler/rustc_error_codes/src/error_codes/E0549.md

diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 8944711f38f..c4330694504 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -290,6 +290,7 @@ E0543: include_str!("./error_codes/E0543.md"),
 E0545: include_str!("./error_codes/E0545.md"),
 E0546: include_str!("./error_codes/E0546.md"),
 E0547: include_str!("./error_codes/E0547.md"),
+E0549: include_str!("./error_codes/E0549.md"),
 E0550: include_str!("./error_codes/E0550.md"),
 E0551: include_str!("./error_codes/E0551.md"),
 E0552: include_str!("./error_codes/E0552.md"),
@@ -608,9 +609,6 @@ E0781: include_str!("./error_codes/E0781.md"),
 //  E0540, // multiple rustc_deprecated attributes
     E0544, // multiple stability levels
 //  E0548, // replaced with a generic attribute input check
-    // rustc_deprecated attribute must be paired with either stable or unstable
-    // attribute
-    E0549,
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
 //  E0558, // replaced with a generic attribute input check
diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
new file mode 100644
index 00000000000..a5728dc20c8
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -0,0 +1,37 @@
+The `rustc_deprecated` attribute must be paired with either `stable` or
+`unstable`.
+
+Erroneous code example:
+
+```compile_fail,E0549
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to add also an attribute `stable` or `unstable`.
+Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "1.0.0", feature = "test")]
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index 715eb00974e..03fb80bb90a 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -116,5 +116,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")]
 
 error: aborting due to 19 previous errors
 
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0550.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0549, E0550.
 For more information about an error, try `rustc --explain E0539`.

From 5112cf0282e339af3e2f3bbe872fd32dfd69df56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= <jesusprubio@gmail.com>
Date: Thu, 18 Feb 2021 09:23:21 +0100
Subject: [PATCH 16/20] Update
 compiler/rustc_error_codes/src/error_codes/E0549.md

Co-authored-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
---
 compiler/rustc_error_codes/src/error_codes/E0549.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
index a5728dc20c8..0ae7b0a377f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0549.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -1,5 +1,5 @@
-The `rustc_deprecated` attribute must be paired with either `stable` or
-`unstable`.
+A `rustc_deprecated` attribute wasn't be paired with a `stable`/`unstable`
+attribute. 
 
 Erroneous code example:
 

From 0e01c41c02d7d8ec4217e5ca9fa55281accd99a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= <jesusprubio@gmail.com>
Date: Thu, 18 Feb 2021 09:38:42 +0100
Subject: [PATCH 17/20] Update
 compiler/rustc_error_codes/src/error_codes/E0549.md

Co-authored-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
---
 compiler/rustc_error_codes/src/error_codes/E0549.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
index 0ae7b0a377f..3337b0964fa 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0549.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -1,4 +1,4 @@
-A `rustc_deprecated` attribute wasn't be paired with a `stable`/`unstable`
+A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
 attribute. 
 
 Erroneous code example:

From 3c4fe1e3dbc1f060d10c2dc974d2c496db4ed74d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= <jesusprubio@gmail.com>
Date: Thu, 18 Feb 2021 10:03:01 +0100
Subject: [PATCH 18/20] Update
 compiler/rustc_error_codes/src/error_codes/E0549.md

Co-authored-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
---
 compiler/rustc_error_codes/src/error_codes/E0549.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
index 3337b0964fa..d4b78e7e0d6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0549.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -1,5 +1,5 @@
 A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
-attribute. 
+attribute.
 
 Erroneous code example:
 

From 6165d1cc72f8af55b3ef16ad81273b80876f9518 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <eddyb@lyken.rs>
Date: Thu, 18 Feb 2021 14:13:38 +0200
Subject: [PATCH 19/20] Print -Ztime-passes (and misc stats/logs) on stderr,
 not stdout.

---
 .../rustc_data_structures/src/profiling.rs    |  2 +-
 .../src/persist/file_format.rs                |  2 +-
 compiler/rustc_incremental/src/persist/fs.rs  |  4 +--
 .../rustc_incremental/src/persist/load.rs     |  2 +-
 compiler/rustc_interface/src/passes.rs        |  6 ++--
 compiler/rustc_metadata/src/rmeta/encoder.rs  | 34 +++++++++----------
 compiler/rustc_middle/src/ty/query/stats.rs   | 22 ++++++------
 .../rustc_mir/src/transform/coverage/tests.rs |  6 ++--
 compiler/rustc_passes/src/hir_stats.rs        | 12 +++----
 .../rustc_query_system/src/dep_graph/graph.rs | 28 +++++++--------
 compiler/rustc_session/src/session.rs         |  8 ++---
 compiler/rustc_span/src/source_map/tests.rs   |  2 +-
 12 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index f0b413c795e..51f851dc946 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -608,7 +608,7 @@ pub fn print_time_passes_entry(
         (None, None) => String::new(),
     };
 
-    println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
+    eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
 }
 
 // Hack up our own formatting for the duration to make it easier for scripts
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 087f83c2475..374a9eb41e5 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -109,7 +109,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
     debug!("read_file: {}", message);
 
     if report_incremental_info {
-        println!(
+        eprintln!(
             "[incremental] ignoring cache artifact `{}`: {}",
             file.file_name().unwrap().to_string_lossy(),
             message
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 7a1976bed4b..c7a6c1195c5 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -440,12 +440,12 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
     }
 
     if sess.opts.debugging_opts.incremental_info {
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                   {} files hard-linked",
             files_linked
         );
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                  {} files copied",
             files_copied
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 0add0c5aa26..2b5649bb059 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -170,7 +170,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 
                 if prev_commandline_args_hash != expected_hash {
                     if report_incremental_info {
-                        println!(
+                        eprintln!(
                             "[incremental] completely ignoring cache because of \
                                     differing commandline arguments"
                         );
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 544da4cd9aa..ed5061125ba 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -64,8 +64,8 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
     }
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Lines of code:             {}", sess.source_map().count_lines());
-        println!("Pre-expansion node count:  {}", count_nodes(&krate));
+        eprintln!("Lines of code:             {}", sess.source_map().count_lines());
+        eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
     }
 
     if let Some(ref s) = sess.opts.debugging_opts.show_span {
@@ -394,7 +394,7 @@ fn configure_and_expand_inner<'a>(
     // Done with macro expansion!
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Post-expansion node count: {}", count_nodes(&krate));
+        eprintln!("Post-expansion node count: {}", count_nodes(&krate));
     }
 
     if sess.opts.debugging_opts.hir_stats {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3314385dbf0..61265d7204c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -695,23 +695,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
             }
 
-            println!("metadata stats:");
-            println!("             dep bytes: {}", dep_bytes);
-            println!("     lib feature bytes: {}", lib_feature_bytes);
-            println!("       lang item bytes: {}", lang_item_bytes);
-            println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
-            println!("          native bytes: {}", native_lib_bytes);
-            println!("      source_map bytes: {}", source_map_bytes);
-            println!("            impl bytes: {}", impl_bytes);
-            println!("    exp. symbols bytes: {}", exported_symbols_bytes);
-            println!("  def-path table bytes: {}", def_path_table_bytes);
-            println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
-            println!("             mir bytes: {}", mir_bytes);
-            println!("            item bytes: {}", item_bytes);
-            println!("           table bytes: {}", tables_bytes);
-            println!("         hygiene bytes: {}", hygiene_bytes);
-            println!("            zero bytes: {}", zero_bytes);
-            println!("           total bytes: {}", total_bytes);
+            eprintln!("metadata stats:");
+            eprintln!("             dep bytes: {}", dep_bytes);
+            eprintln!("     lib feature bytes: {}", lib_feature_bytes);
+            eprintln!("       lang item bytes: {}", lang_item_bytes);
+            eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
+            eprintln!("          native bytes: {}", native_lib_bytes);
+            eprintln!("      source_map bytes: {}", source_map_bytes);
+            eprintln!("            impl bytes: {}", impl_bytes);
+            eprintln!("    exp. symbols bytes: {}", exported_symbols_bytes);
+            eprintln!("  def-path table bytes: {}", def_path_table_bytes);
+            eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
+            eprintln!("             mir bytes: {}", mir_bytes);
+            eprintln!("            item bytes: {}", item_bytes);
+            eprintln!("           table bytes: {}", tables_bytes);
+            eprintln!("         hygiene bytes: {}", hygiene_bytes);
+            eprintln!("            zero bytes: {}", zero_bytes);
+            eprintln!("           total bytes: {}", total_bytes);
         }
 
         root
diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs
index c885a10f805..29ec9c132a8 100644
--- a/compiler/rustc_middle/src/ty/query/stats.rs
+++ b/compiler/rustc_middle/src/ty/query/stats.rs
@@ -67,29 +67,29 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
     if cfg!(debug_assertions) {
         let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
         let results: usize = queries.iter().map(|s| s.entry_count).sum();
-        println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
+        eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
     }
 
     let mut query_key_sizes = queries.clone();
     query_key_sizes.sort_by_key(|q| q.key_size);
-    println!("\nLarge query keys:");
+    eprintln!("\nLarge query keys:");
     for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
     }
 
     let mut query_value_sizes = queries.clone();
     query_value_sizes.sort_by_key(|q| q.value_size);
-    println!("\nLarge query values:");
+    eprintln!("\nLarge query values:");
     for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
     }
 
     if cfg!(debug_assertions) {
         let mut query_cache_hits = queries.clone();
         query_cache_hits.sort_by_key(|q| q.cache_hits);
-        println!("\nQuery cache hits:");
+        eprintln!("\nQuery cache hits:");
         for q in query_cache_hits.iter().rev() {
-            println!(
+            eprintln!(
                 "   {} - {} ({}%)",
                 q.name,
                 q.cache_hits,
@@ -100,19 +100,19 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
 
     let mut query_value_count = queries.clone();
     query_value_count.sort_by_key(|q| q.entry_count);
-    println!("\nQuery value count:");
+    eprintln!("\nQuery value count:");
     for q in query_value_count.iter().rev() {
-        println!("   {} - {}", q.name, q.entry_count);
+        eprintln!("   {} - {}", q.name, q.entry_count);
     }
 
     let mut def_id_density: Vec<_> =
         queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
     def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
-    println!("\nLocal DefId density:");
+    eprintln!("\nLocal DefId density:");
     let total = tcx.hir().definitions().def_index_count() as f64;
     for q in def_id_density.iter().rev() {
         let local = q.local_def_id_keys.unwrap();
-        println!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
+        eprintln!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
index d36f1b8e5f6..7a9bfaad883 100644
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ b/compiler/rustc_mir/src/transform/coverage/tests.rs
@@ -327,7 +327,7 @@ macro_rules! assert_successors {
 fn test_covgraph_goto_switchint() {
     let mir_body = goto_switchint();
     if false {
-        println!("basic_blocks = {}", debug_basic_blocks(&mir_body));
+        eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
     }
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
@@ -583,11 +583,11 @@ fn test_find_loop_backedges_none() {
     let mir_body = goto_switchint();
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     if false {
-        println!(
+        eprintln!(
             "basic_coverage_blocks = {:?}",
             basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
         );
-        println!("successors = {:?}", basic_coverage_blocks.successors);
+        eprintln!("successors = {:?}", basic_coverage_blocks.successors);
     }
     let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
     assert_eq!(
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index e35ad10968d..8d5a5bdf6b7 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -66,13 +66,13 @@ impl<'k> StatCollector<'k> {
 
         let mut total_size = 0;
 
-        println!("\n{}\n", title);
+        eprintln!("\n{}\n", title);
 
-        println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
-        println!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
+        eprintln!("----------------------------------------------------------------");
 
         for (label, data) in stats {
-            println!(
+            eprintln!(
                 "{:<18}{:>18}{:>14}{:>14}",
                 label,
                 to_readable_str(data.count * data.size),
@@ -82,8 +82,8 @@ impl<'k> StatCollector<'k> {
 
             total_size += data.count * data.size;
         }
-        println!("----------------------------------------------------------------");
-        println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+        eprintln!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
     }
 }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 4fb3a683ea2..b13aa2f6ccb 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -964,29 +964,29 @@ impl<K: DepKind> DepGraph<K> {
                                  ----------------------------------------------\
                                  ------------";
 
-        println!("[incremental]");
-        println!("[incremental] DepGraph Statistics");
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
-        println!("[incremental] Total Node Count: {}", total_node_count);
-        println!("[incremental] Total Edge Count: {}", total_edge_count);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] DepGraph Statistics");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] Total Node Count: {}", total_node_count);
+        eprintln!("[incremental] Total Edge Count: {}", total_edge_count);
 
         if cfg!(debug_assertions) {
             let total_edge_reads = current.total_read_count.load(Relaxed);
             let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
 
-            println!("[incremental] Total Edge Reads: {}", total_edge_reads);
-            println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
+            eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads);
+            eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
         }
 
-        println!("[incremental]");
+        eprintln!("[incremental]");
 
-        println!(
+        eprintln!(
             "[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
             "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
         );
 
-        println!(
+        eprintln!(
             "[incremental] -------------------------------------\
                   |------------------\
                   |-------------\
@@ -997,7 +997,7 @@ impl<K: DepKind> DepGraph<K> {
             let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
             let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
 
-            println!(
+            eprintln!(
                 "[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
                 format!("{:?}", stat.kind),
                 node_kind_ratio,
@@ -1006,8 +1006,8 @@ impl<K: DepKind> DepGraph<K> {
             );
         }
 
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
     }
 
     fn next_virtual_depnode_index(&self) -> DepNodeIndex {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index a7ceb9e06a5..823aa61c470 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -959,19 +959,19 @@ impl Session {
     }
 
     pub fn print_perf_stats(&self) {
-        println!(
+        eprintln!(
             "Total time spent computing symbol hashes:      {}",
             duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
         );
-        println!(
+        eprintln!(
             "Total queries canonicalized:                   {}",
             self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_generic_arg_after_erasing_regions:   {}",
             self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_projection_ty:                       {}",
             self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
         );
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3f22829b049..0aca677248b 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -243,7 +243,7 @@ impl SourceMapExtension for SourceMap {
         substring: &str,
         n: usize,
     ) -> Span {
-        println!(
+        eprintln!(
             "span_substr(file={:?}/{:?}, substring={:?}, n={})",
             file.name, file.start_pos, substring, n
         );

From 8a5c5681da3695e1c2e3f23bee43a7ebfdce6161 Mon Sep 17 00:00:00 2001
From: Nathan Nguyen <nathan.tm.nguyen@gmail.com>
Date: Wed, 17 Feb 2021 23:44:37 -0600
Subject: [PATCH 20/20] nhwn: optimize counting digits in line numbers

---
 compiler/rustc_errors/src/emitter.rs | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index ea62e215230..42c3d5e48fe 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1713,7 +1713,18 @@ impl EmitterWriter {
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
         } else {
-            self.get_max_line_num(span, children).to_string().len()
+            // Instead of using .to_string().len(), we iteratively count the
+            // number of digits to avoid allocation. This strategy has sizable
+            // performance gains over the old string strategy.
+            let mut n = self.get_max_line_num(span, children);
+            let mut num_digits = 0;
+            loop {
+                num_digits += 1;
+                n /= 10;
+                if n == 0 {
+                    break num_digits;
+                }
+            }
         };
 
         match self.emit_message_default(span, message, code, level, max_line_num_len, false) {