From 3ab95ceb12b60c1564d037e8d8d6e2406fad44b3 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 7 Jan 2020 00:00:16 +0000
Subject: [PATCH 01/25] Detail transitive containment in E0588 diagnostic

---
 src/librustc_typeck/check/mod.rs              |  87 ++++++++++----
 .../ui/repr/repr-packed-contains-align.rs     |  16 +--
 .../ui/repr/repr-packed-contains-align.stderr | 112 ++++++++++++++++--
 3 files changed, 174 insertions(+), 41 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index eacd94f7da7f7..6b9b28a0fa622 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -118,7 +118,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
+use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
 use rustc_index::vec::Idx;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
@@ -2295,44 +2295,81 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
                 "type has conflicting packed and align representation hints"
             )
             .emit();
-        } else if check_packed_inner(tcx, def_id, &mut Vec::new()) {
-            struct_span_err!(
-                tcx.sess,
-                sp,
-                E0588,
-                "packed type cannot transitively contain a `[repr(align)]` type"
-            )
-            .emit();
+        } else {
+            if let Some(def_spans) = check_packed_inner(tcx, def_id, &mut vec![]) {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    sp,
+                    E0588,
+                    "packed type cannot transitively contain a `#[repr(align)]` type"
+                );
+
+                let hir = tcx.hir();
+                if let Some(hir_id) = hir.as_local_hir_id(def_spans[0].0) {
+                    if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
+                        err.span_note(
+                            tcx.def_span(def_spans[0].0),
+                            &format!("`{}` has a `#[repr(align)]` attribute", ident),
+                        );
+                    }
+                }
+
+                if def_spans.len() > 2 {
+                    let mut first = true;
+                    for (adt_def, span) in def_spans.iter().skip(1).rev() {
+                        if let Some(hir_id) = hir.as_local_hir_id(*adt_def) {
+                            if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
+                                err.span_note(
+                                    *span,
+                                    &if first {
+                                        format!(
+                                            "`{}` contains a field of type `{}`",
+                                            tcx.type_of(def_id),
+                                            ident
+                                        )
+                                    } else {
+                                        format!("...which contains a field of type `{}`", ident)
+                                    },
+                                );
+                                first = false;
+                            }
+                        }
+                    }
+                }
+
+                err.emit();
+            }
         }
     }
 }
 
-fn check_packed_inner(tcx: TyCtxt<'_>, def_id: DefId, stack: &mut Vec<DefId>) -> bool {
-    let t = tcx.type_of(def_id);
-    if stack.contains(&def_id) {
-        debug!("check_packed_inner: {:?} is recursive", t);
-        return false;
-    }
-    if let ty::Adt(def, substs) = t.kind {
+fn check_packed_inner(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    stack: &mut Vec<DefId>,
+) -> Option<Vec<(DefId, Span)>> {
+    if let ty::Adt(def, substs) = tcx.type_of(def_id).kind {
         if def.is_struct() || def.is_union() {
-            if tcx.adt_def(def.did).repr.align.is_some() {
-                return true;
+            if def.repr.align.is_some() {
+                return Some(vec![(def.did, DUMMY_SP)]);
             }
-            // push struct def_id before checking fields
+
             stack.push(def_id);
             for field in &def.non_enum_variant().fields {
-                let f = field.ty(tcx, substs);
-                if let ty::Adt(def, _) = f.kind {
-                    if check_packed_inner(tcx, def.did, stack) {
-                        return true;
+                if let ty::Adt(def, _) = field.ty(tcx, substs).kind {
+                    if !stack.contains(&def.did) {
+                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
+                            defs.push((def.did, field.ident.span));
+                            return Some(defs);
+                        }
                     }
                 }
             }
-            // only need to pop if not early out
             stack.pop();
         }
     }
-    false
+
+    None
 }
 
 /// Emit an error when encountering more or less than one variant in a transparent enum.
diff --git a/src/test/ui/repr/repr-packed-contains-align.rs b/src/test/ui/repr/repr-packed-contains-align.rs
index a3610345173a7..67d87eb5cd520 100644
--- a/src/test/ui/repr/repr-packed-contains-align.rs
+++ b/src/test/ui/repr/repr-packed-contains-align.rs
@@ -16,34 +16,34 @@ union UB {
 }
 
 #[repr(packed)]
-struct SC(SA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+struct SC(SA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
 
 #[repr(packed)]
-struct SD(SB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+struct SD(SB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
 
 #[repr(packed)]
-struct SE(UA); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+struct SE(UA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
 
 #[repr(packed)]
-struct SF(UB); //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+struct SF(UB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
 
 #[repr(packed)]
-union UC { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+union UC { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
     a: UA
 }
 
 #[repr(packed)]
-union UD { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+union UD { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
     n: UB
 }
 
 #[repr(packed)]
-union UE { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+union UE { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
     a: SA
 }
 
 #[repr(packed)]
-union UF { //~ ERROR: packed type cannot transitively contain a `[repr(align)]` type
+union UF { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type
     n: SB
 }
 
diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr
index df001d6b5f2a4..32f9bb8bf33d9 100644
--- a/src/test/ui/repr/repr-packed-contains-align.stderr
+++ b/src/test/ui/repr/repr-packed-contains-align.stderr
@@ -1,58 +1,154 @@
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:19:1
    |
 LL | struct SC(SA);
    | ^^^^^^^^^^^^^^
+   |
+note: `SA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:5:1
+   |
+LL | struct SA(i32);
+   | ^^^^^^^^^^^^^^^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:22:1
    |
 LL | struct SD(SB);
    | ^^^^^^^^^^^^^^
+   |
+note: `SA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:5:1
+   |
+LL | struct SA(i32);
+   | ^^^^^^^^^^^^^^^
+note: `SD` contains a field of type `SB`
+  --> $DIR/repr-packed-contains-align.rs:22:11
+   |
+LL | struct SD(SB);
+   |           ^^
+note: ...which contains a field of type `SA`
+  --> $DIR/repr-packed-contains-align.rs:7:11
+   |
+LL | struct SB(SA);
+   |           ^^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:25:1
    |
 LL | struct SE(UA);
    | ^^^^^^^^^^^^^^
+   |
+note: `UA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:10:1
+   |
+LL | / union UA {
+LL | |     i: i32
+LL | | }
+   | |_^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:28:1
    |
 LL | struct SF(UB);
    | ^^^^^^^^^^^^^^
+   |
+note: `UA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:10:1
+   |
+LL | / union UA {
+LL | |     i: i32
+LL | | }
+   | |_^
+note: `SF` contains a field of type `UB`
+  --> $DIR/repr-packed-contains-align.rs:28:11
+   |
+LL | struct SF(UB);
+   |           ^^
+note: ...which contains a field of type `UA`
+  --> $DIR/repr-packed-contains-align.rs:15:5
+   |
+LL |     a: UA
+   |     ^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:31:1
    |
 LL | / union UC {
 LL | |     a: UA
+LL | | }
+   | |_^
+   |
+note: `UA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:10:1
+   |
+LL | / union UA {
+LL | |     i: i32
 LL | | }
    | |_^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:36:1
    |
 LL | / union UD {
 LL | |     n: UB
 LL | | }
    | |_^
+   |
+note: `UA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:10:1
+   |
+LL | / union UA {
+LL | |     i: i32
+LL | | }
+   | |_^
+note: `UD` contains a field of type `UB`
+  --> $DIR/repr-packed-contains-align.rs:37:5
+   |
+LL |     n: UB
+   |     ^
+note: ...which contains a field of type `UA`
+  --> $DIR/repr-packed-contains-align.rs:15:5
+   |
+LL |     a: UA
+   |     ^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:41:1
    |
 LL | / union UE {
 LL | |     a: SA
 LL | | }
    | |_^
+   |
+note: `SA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:5:1
+   |
+LL | struct SA(i32);
+   | ^^^^^^^^^^^^^^^
 
-error[E0588]: packed type cannot transitively contain a `[repr(align)]` type
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
   --> $DIR/repr-packed-contains-align.rs:46:1
    |
 LL | / union UF {
 LL | |     n: SB
 LL | | }
    | |_^
+   |
+note: `SA` has a `#[repr(align)]` attribute
+  --> $DIR/repr-packed-contains-align.rs:5:1
+   |
+LL | struct SA(i32);
+   | ^^^^^^^^^^^^^^^
+note: `UF` contains a field of type `SB`
+  --> $DIR/repr-packed-contains-align.rs:47:5
+   |
+LL |     n: SB
+   |     ^
+note: ...which contains a field of type `SA`
+  --> $DIR/repr-packed-contains-align.rs:7:11
+   |
+LL | struct SB(SA);
+   |           ^^
 
 error: aborting due to 8 previous errors
 

From 6fd564112f1ec00f6f8a56e8a3577dd255639131 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 13:13:12 -0800
Subject: [PATCH 02/25] Specific error for unsized `dyn Trait` return type

Suggest `impl Trait` when possible, and `Box<dyn Trait>` otherwise.
---
 src/librustc/traits/error_reporting.rs        | 201 +++++++++++++++++-
 src/librustc/traits/mod.rs                    |  11 +
 src/librustc_error_codes/error_codes.rs       |   1 +
 src/test/ui/error-codes/E0746.rs              |  17 ++
 src/test/ui/error-codes/E0746.stderr          |  62 ++++++
 .../dyn-trait-return-should-be-impl-trait.rs  |  36 ++++
 ...n-trait-return-should-be-impl-trait.stderr | 186 ++++++++++++++++
 7 files changed, 512 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/error-codes/E0746.rs
 create mode 100644 src/test/ui/error-codes/E0746.stderr
 create mode 100644 src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
 create mode 100644 src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr

diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 7f151af7abe50..8f771658e4098 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use super::{
     ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode,
     MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause,
@@ -22,9 +23,12 @@ use crate::ty::TypeckTables;
 use crate::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
+use rustc_errors::{
+    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym};
@@ -758,7 +762,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 )),
                                 Some(
                                     "the question mark operation (`?`) implicitly performs a \
-                                 conversion on the error value using the `From` trait"
+                                     conversion on the error value using the `From` trait"
                                         .to_owned(),
                                 ),
                             )
@@ -835,6 +839,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
                         self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
                         self.note_version_mismatch(&mut err, &trait_ref);
+                        if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
+                            err.emit();
+                            return;
+                        }
 
                         // Try to report a help message
                         if !trait_ref.has_infer_types()
@@ -1696,6 +1704,195 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_impl_trait(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        span: Span,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+    ) -> bool {
+        if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() {
+        } else {
+            return false;
+        }
+
+        let hir = self.tcx.hir();
+        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let node = hir.find(parent_node);
+        if let Some(hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(sig, _, body_id), ..
+        })) = node
+        {
+            let body = hir.body(*body_id);
+            let trait_ref = self.resolve_vars_if_possible(trait_ref);
+            let ty = trait_ref.skip_binder().self_ty();
+            if let ty::Dynamic(..) = ty.kind {
+            } else {
+                // We only want to suggest `impl Trait` to `dyn Trait`s.
+                // For example, `fn foo() -> str` needs to be filtered out.
+                return false;
+            }
+            // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
+            // cases like `fn foo() -> (dyn Trait, i32) {}`.
+            // Recursively look for `TraitObject` types and if there's only one, use that span to
+            // suggest `impl Trait`.
+
+            struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
+
+            impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
+                type Map = rustc::hir::map::Map<'v>;
+
+                fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
+                    hir::intravisit::NestedVisitorMap::None
+                }
+
+                fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                    match ex.kind {
+                        hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
+                        _ => {}
+                    }
+                    hir::intravisit::walk_expr(self, ex);
+                }
+
+                fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+                    if body.generator_kind().is_none() {
+                        if let hir::ExprKind::Block(block, None) = body.value.kind {
+                            if let Some(expr) = block.expr {
+                                self.0.push(expr);
+                            }
+                        }
+                    }
+                    hir::intravisit::walk_body(self, body);
+                }
+            }
+
+            // Visit to make sure there's a single `return` type to suggest `impl Trait`,
+            // otherwise suggest using `Box<dyn Trait>` or an enum.
+            let mut visitor = ReturnsVisitor(vec![]);
+            visitor.visit_body(&body);
+
+            let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+
+            if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
+                let mut all_returns_conform_to_trait = true;
+                let mut all_returns_have_same_type = true;
+                let mut last_ty = None;
+                if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
+                    let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
+                    if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
+                        for predicate in predicates.iter() {
+                            for expr in &visitor.0 {
+                                if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                                    if let Some(ty) = last_ty {
+                                        all_returns_have_same_type &= ty == returned_ty;
+                                    }
+                                    last_ty = Some(returned_ty);
+
+                                    let param_env = ty::ParamEnv::empty();
+                                    let pred = predicate.with_self_ty(self.tcx, returned_ty);
+                                    let obligation =
+                                        Obligation::new(cause.clone(), param_env, pred);
+                                    all_returns_conform_to_trait &=
+                                        self.predicate_may_hold(&obligation);
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    // We still want to verify whether all the return types conform to each other.
+                    for expr in &visitor.0 {
+                        if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                            if let Some(ty) = last_ty {
+                                all_returns_have_same_type &= ty == returned_ty;
+                            }
+                            last_ty = Some(returned_ty);
+                        }
+                    }
+                }
+
+                if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
+                    ret_ty.span.overlaps(span),
+                    &ret_ty.kind,
+                    self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
+                    all_returns_conform_to_trait,
+                    last_ty,
+                ) {
+                    err.code = Some(error_code!(E0746));
+                    err.set_primary_message(
+                        "return type cannot have a bare trait because it must be `Sized`",
+                    );
+                    err.children.clear();
+                    let impl_trait_msg = "for information on `impl Trait`, see \
+                        <https://doc.rust-lang.org/book/ch10-02-traits.html\
+                        #returning-types-that-implement-traits>";
+                    let trait_obj_msg = "for information on trait objects, see \
+                        <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
+                        #using-trait-objects-that-allow-for-values-of-different-types>";
+                    let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
+                    let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
+                    if all_returns_have_same_type {
+                        err.span_suggestion(
+                            ret_ty.span,
+                            &format!(
+                                "you can use the `impl Trait` feature \
+                                 in the return type because all the return paths are of type \
+                                 `{}`, which implements `dyn {}`",
+                                last_ty, trait_obj,
+                            ),
+                            format!("impl {}", trait_obj),
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.note(impl_trait_msg);
+                    } else {
+                        let mut suggestions = visitor
+                            .0
+                            .iter()
+                            .map(|expr| {
+                                (
+                                    expr.span,
+                                    format!(
+                                        "Box::new({})",
+                                        self.tcx
+                                            .sess
+                                            .source_map()
+                                            .span_to_snippet(expr.span)
+                                            .unwrap()
+                                    ),
+                                )
+                            })
+                            .collect::<Vec<_>>();
+                        suggestions.push((
+                            ret_ty.span,
+                            format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
+                        ));
+                        err.multipart_suggestion(
+                            "if the performance implications are acceptable, you can return a \
+                             trait object",
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.span_help(
+                            visitor.0.iter().map(|expr| expr.span).collect::<Vec<_>>(),
+                            &format!(
+                                "if all the returned values were of the same type you could use \
+                                 `impl {}` as the return type",
+                                trait_obj,
+                            ),
+                        );
+                        err.help(
+                            "alternatively, you can always create a new `enum` with a variant \
+                             for each returned type",
+                        );
+                        err.note(impl_trait_msg);
+                        err.note(trait_obj_msg);
+                    }
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     /// Given some node representing a fn-like thing in the HIR map,
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 31de5409fc8be..f68711c06205b 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -1171,6 +1171,17 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 }
 
+impl<'tcx> ObligationCauseCode<'tcx> {
+    pub fn peel_derives(&self) -> &Self {
+        match self {
+            BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) => {
+                cause.parent_code.peel_derives()
+            }
+            _ => self,
+        }
+    }
+}
+
 impl<'tcx, N> Vtable<'tcx, N> {
     pub fn nested_obligations(self) -> Vec<N> {
         match self {
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 272147e28a419..c17cb7dd9f161 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -608,4 +608,5 @@ E0745: include_str!("./error_codes/E0745.md"),
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
     E0727, // `async` generators are not yet supported
     E0739, // invalid track_caller application/syntax
+    E0746, // `dyn Trait` return type
 }
diff --git a/src/test/ui/error-codes/E0746.rs b/src/test/ui/error-codes/E0746.rs
new file mode 100644
index 0000000000000..ad257b01e1b40
--- /dev/null
+++ b/src/test/ui/error-codes/E0746.rs
@@ -0,0 +1,17 @@
+struct Struct;
+trait Trait {}
+impl Trait for Struct {}
+impl Trait for u32 {}
+
+fn foo() -> dyn Trait { Struct }
+//~^ ERROR E0746
+//~| ERROR E0308
+
+fn bar() -> dyn Trait { //~ ERROR E0746
+    if true {
+        return 0; //~ ERROR E0308
+    }
+    42 //~ ERROR E0308
+}
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr
new file mode 100644
index 0000000000000..baafcd27c29d4
--- /dev/null
+++ b/src/test/ui/error-codes/E0746.stderr
@@ -0,0 +1,62 @@
+error[E0308]: mismatched types
+  --> $DIR/E0746.rs:6:25
+   |
+LL | fn foo() -> dyn Trait { Struct }
+   |             ---------   ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |             |
+   |             expected `(dyn Trait + 'static)` because of return type
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/E0746.rs:6:13
+   |
+LL | fn foo() -> dyn Trait { Struct }
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+   |
+LL | fn foo() -> impl Trait { Struct }
+   |             ^^^^^^^^^^
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/E0746.rs:10:13
+   |
+LL | fn bar() -> dyn Trait {
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+help: you can use the `impl Trait` feature in the return type because all the return paths are of type `{integer}`, which implements `dyn Trait`
+   |
+LL | fn bar() -> impl Trait {
+   |             ^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/E0746.rs:12:16
+   |
+LL | fn bar() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+LL |     if true {
+LL |         return 0;
+   |                ^ expected trait `Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                      found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/E0746.rs:14:5
+   |
+LL | fn bar() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+...
+LL |     42
+   |     ^^ expected trait `Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                      found type `{integer}`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
new file mode 100644
index 0000000000000..80168ca825774
--- /dev/null
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
@@ -0,0 +1,36 @@
+#![allow(bare_trait_objects)]
+struct Struct;
+trait Trait {}
+impl Trait for Struct {}
+impl Trait for u32 {}
+
+fn fuz() -> (usize, Trait) { (42, Struct) }
+//~^ ERROR E0277
+//~| ERROR E0308
+fn bar() -> (usize, dyn Trait) { (42, Struct) }
+//~^ ERROR E0277
+//~| ERROR E0308
+fn bap() -> Trait { Struct }
+//~^ ERROR E0746
+//~| ERROR E0308
+fn ban() -> dyn Trait { Struct }
+//~^ ERROR E0746
+//~| ERROR E0308
+fn bak() -> dyn Trait { unimplemented!() } //~ ERROR E0277
+// Suggest using `Box<dyn Trait>`
+fn bal() -> dyn Trait { //~ ERROR E0746
+    if true {
+        return Struct; //~ ERROR E0308
+    }
+    42 //~ ERROR E0308
+}
+
+// Suggest using `impl Trait`
+fn bat() -> dyn Trait { //~ ERROR E0746
+    if true {
+        return 0; //~ ERROR E0308
+    }
+    42 //~ ERROR E0308
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
new file mode 100644
index 0000000000000..ce4c141a0af9d
--- /dev/null
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -0,0 +1,186 @@
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:35
+   |
+LL | fn fuz() -> (usize, Trait) { (42, Struct) }
+   |                                   ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
+   |
+LL | fn fuz() -> (usize, Trait) { (42, Struct) }
+   |             ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
+   = note: the return type of a function must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:39
+   |
+LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
+   |                                       ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
+   |
+LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
+   |             ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
+   = note: the return type of a function must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:21
+   |
+LL | fn bap() -> Trait { Struct }
+   |             -----   ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |             |
+   |             expected `(dyn Trait + 'static)` because of return type
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13
+   |
+LL | fn bap() -> Trait { Struct }
+   |             ^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+   |
+LL | fn bap() -> impl Trait { Struct }
+   |             ^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:25
+   |
+LL | fn ban() -> dyn Trait { Struct }
+   |             ---------   ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |             |
+   |             expected `(dyn Trait + 'static)` because of return type
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:13
+   |
+LL | fn ban() -> dyn Trait { Struct }
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+   |
+LL | fn ban() -> impl Trait { Struct }
+   |             ^^^^^^^^^^
+
+error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
+   |
+LL | fn bak() -> dyn Trait { unimplemented!() }
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: the return type of a function must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:16
+   |
+LL | fn bal() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+LL |     if true {
+LL |         return Struct;
+   |                ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                    found struct `Struct`
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:21:13
+   |
+LL | fn bal() -> dyn Trait {
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+help: if all the returned values were of the same type you could use `impl Trait` as the return type
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5
+   |
+LL |         return Struct;
+   |                ^^^^^^
+LL |     }
+LL |     42
+   |     ^^
+   = help: alternatively, you can always create a new `enum` with a variant for each returned type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+help: if the performance implications are acceptable, you can return a trait object
+   |
+LL | fn bal() -> Box<dyn Trait> {
+LL |     if true {
+LL |         return Box::new(Struct);
+LL |     }
+LL |     Box::new(42)
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5
+   |
+LL | fn bal() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+...
+LL |     42
+   |     ^^ expected trait `Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                      found type `{integer}`
+
+error[E0746]: return type cannot have a bare trait because it must be `Sized`
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:13
+   |
+LL | fn bat() -> dyn Trait {
+   |             ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+help: you can use the `impl Trait` feature in the return type because all the return paths are of type `{integer}`, which implements `dyn Trait`
+   |
+LL | fn bat() -> impl Trait {
+   |             ^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:31:16
+   |
+LL | fn bat() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+LL |     if true {
+LL |         return 0;
+   |                ^ expected trait `Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                      found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:33:5
+   |
+LL | fn bat() -> dyn Trait {
+   |             --------- expected `(dyn Trait + 'static)` because of return type
+...
+LL |     42
+   |     ^^ expected trait `Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait + 'static)`
+                      found type `{integer}`
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.

From 75eabb17aec390fd91b5bf11539012e4fc7307b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 13:14:11 -0800
Subject: [PATCH 03/25] Account for diverging types in return `impl Trait`

---
 src/librustc_typeck/check/coercion.rs         | 28 +++++++++++++++++
 src/test/ui/impl-trait/equality.stderr        |  5 ++++
 ...type-err-cause-on-impl-trait-return.stderr | 30 +++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 1afb703ca1506..698fdfa3897b1 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1348,6 +1348,34 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 "...is found to be `{}` here",
                 fcx.resolve_vars_with_obligations(expected),
             ));
+            err.note(
+                "`impl Trait` as a return type requires that all the returned values must have \
+                 the same type",
+            );
+            let snippet = fcx
+                .tcx
+                .sess
+                .source_map()
+                .span_to_snippet(return_sp)
+                .unwrap_or_else(|_| "dyn Trait".to_string());
+            let mut snippet_iter = snippet.split_whitespace();
+            let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
+            if has_impl {
+                err.help(&format!(
+                    "you can instead return a trait object using `Box<dyn {}>`",
+                    &snippet[5..]
+                ));
+            }
+            let impl_trait_msg = "for information on `impl Trait`, see \
+                <https://doc.rust-lang.org/book/ch10-02-traits.html\
+                #returning-types-that-implement-traits>";
+            let trait_obj_msg = "for information on trait objects, see \
+                <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
+                #using-trait-objects-that-allow-for-values-of-different-types>";
+            err.note(impl_trait_msg);
+            if has_impl {
+                err.note(trait_obj_msg);
+            }
         }
         err
     }
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index e53524e58d663..215b6d52918ab 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -9,6 +9,11 @@ LL |         return 1_i32;
 LL |     }
 LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn Foo>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
index 27b86007451d8..9db5250e4d876 100644
--- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -9,6 +9,11 @@ LL |         return 0i32;
 LL |     }
 LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
@@ -21,6 +26,11 @@ LL |         return 0i32;
 LL |     } else {
 LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
@@ -33,6 +43,11 @@ LL |         return 0i32;
 LL |     } else {
 LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
@@ -57,6 +72,11 @@ LL |         0 => return 0i32,
    |                     ---- ...is found to be `i32` here
 LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
@@ -71,6 +91,11 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
@@ -83,6 +108,11 @@ LL |             return 0i32;
 ...
 LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
+   |
+   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
 error: aborting due to 7 previous errors
 

From ea7e885204e1ed6b18406e84708abef748925ec5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 16:12:44 -0800
Subject: [PATCH 04/25] Elide E0308 errors in favor of E0746

When a type error involves a `dyn Trait` as the return type, do not emit
the type error, as the "return type is not `Sized`" error will provide
enough information to the user.
---
 src/librustc_typeck/check/coercion.rs         | 19 ++++-
 src/librustc_typeck/check/mod.rs              | 12 +++
 src/test/ui/error-codes/E0746.rs              |  5 +-
 src/test/ui/error-codes/E0746.stderr          | 40 +--------
 .../dyn-trait-return-should-be-impl-trait.rs  | 10 +--
 ...n-trait-return-should-be-impl-trait.stderr | 82 ++-----------------
 6 files changed, 44 insertions(+), 124 deletions(-)

diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 698fdfa3897b1..77f16fb79141d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1222,6 +1222,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 };
 
                 let mut err;
+                let mut unsized_return = false;
                 match cause.code {
                     ObligationCauseCode::ReturnNoExpression => {
                         err = struct_span_err!(
@@ -1243,6 +1244,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             parent_id,
                             expression.map(|expr| (expr, blk_id)),
                         );
+                        if !fcx.tcx.features().unsized_locals {
+                            unsized_return = fcx.is_unsized_return(blk_id);
+                        }
                     }
                     ObligationCauseCode::ReturnValue(id) => {
                         err = self.report_return_mismatched_types(
@@ -1254,6 +1258,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             id,
                             None,
                         );
+                        if !fcx.tcx.features().unsized_locals {
+                            let id = fcx.tcx.hir().get_parent_node(id);
+                            unsized_return = fcx.is_unsized_return(id);
+                        }
                     }
                     _ => {
                         err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
@@ -1282,7 +1290,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
                     .is_some();
 
-                err.emit_unless(assign_to_bool);
+                if unsized_return {
+                    fcx.tcx.sess.delay_span_bug(
+                        cause.span,
+                        &format!(
+                            "elided E0308 in favor of more detailed E0277 or E0746: {:?}",
+                            cause.code
+                        ),
+                    );
+                }
+                err.emit_unless(assign_to_bool || unsized_return);
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index baf9ae1ac2911..8f531ea6199e1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4964,6 +4964,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn is_unsized_return(&self, blk_id: hir::HirId) -> bool {
+        if let Some((fn_decl, _)) = self.get_fn_decl(blk_id) {
+            if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                if let ty::Dynamic(..) = ty.kind {
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     /// A possible error is to forget to add a return type that is needed:
     ///
     /// ```
diff --git a/src/test/ui/error-codes/E0746.rs b/src/test/ui/error-codes/E0746.rs
index ad257b01e1b40..c9ab455a4c5b4 100644
--- a/src/test/ui/error-codes/E0746.rs
+++ b/src/test/ui/error-codes/E0746.rs
@@ -5,13 +5,12 @@ impl Trait for u32 {}
 
 fn foo() -> dyn Trait { Struct }
 //~^ ERROR E0746
-//~| ERROR E0308
 
 fn bar() -> dyn Trait { //~ ERROR E0746
     if true {
-        return 0; //~ ERROR E0308
+        return 0;
     }
-    42 //~ ERROR E0308
+    42
 }
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr
index baafcd27c29d4..44bd0d7ed7d37 100644
--- a/src/test/ui/error-codes/E0746.stderr
+++ b/src/test/ui/error-codes/E0746.stderr
@@ -1,14 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/E0746.rs:6:25
-   |
-LL | fn foo() -> dyn Trait { Struct }
-   |             ---------   ^^^^^^ expected trait `Trait`, found struct `Struct`
-   |             |
-   |             expected `(dyn Trait + 'static)` because of return type
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                    found struct `Struct`
-
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
   --> $DIR/E0746.rs:6:13
    |
@@ -22,7 +11,7 @@ LL | fn foo() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/E0746.rs:10:13
+  --> $DIR/E0746.rs:9:13
    |
 LL | fn bar() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
@@ -33,30 +22,5 @@ help: you can use the `impl Trait` feature in the return type because all the re
 LL | fn bar() -> impl Trait {
    |             ^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/E0746.rs:12:16
-   |
-LL | fn bar() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-LL |     if true {
-LL |         return 0;
-   |                ^ expected trait `Trait`, found integer
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                      found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/E0746.rs:14:5
-   |
-LL | fn bar() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-...
-LL |     42
-   |     ^^ expected trait `Trait`, found integer
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                      found type `{integer}`
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
index 80168ca825774..b70a51dc82511 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs
@@ -12,25 +12,23 @@ fn bar() -> (usize, dyn Trait) { (42, Struct) }
 //~| ERROR E0308
 fn bap() -> Trait { Struct }
 //~^ ERROR E0746
-//~| ERROR E0308
 fn ban() -> dyn Trait { Struct }
 //~^ ERROR E0746
-//~| ERROR E0308
 fn bak() -> dyn Trait { unimplemented!() } //~ ERROR E0277
 // Suggest using `Box<dyn Trait>`
 fn bal() -> dyn Trait { //~ ERROR E0746
     if true {
-        return Struct; //~ ERROR E0308
+        return Struct;
     }
-    42 //~ ERROR E0308
+    42
 }
 
 // Suggest using `impl Trait`
 fn bat() -> dyn Trait { //~ ERROR E0746
     if true {
-        return 0; //~ ERROR E0308
+        return 0;
     }
-    42 //~ ERROR E0308
+    42
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index ce4c141a0af9d..a09ce2bb29863 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -38,17 +38,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:21
-   |
-LL | fn bap() -> Trait { Struct }
-   |             -----   ^^^^^^ expected trait `Trait`, found struct `Struct`
-   |             |
-   |             expected `(dyn Trait + 'static)` because of return type
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                    found struct `Struct`
-
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13
    |
@@ -61,19 +50,8 @@ help: you can use the `impl Trait` feature in the return type because all the re
 LL | fn bap() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:25
-   |
-LL | fn ban() -> dyn Trait { Struct }
-   |             ---------   ^^^^^^ expected trait `Trait`, found struct `Struct`
-   |             |
-   |             expected `(dyn Trait + 'static)` because of return type
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                    found struct `Struct`
-
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:13
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
    |
 LL | fn ban() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
@@ -85,7 +63,7 @@ LL | fn ban() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13
    |
 LL | fn bak() -> dyn Trait { unimplemented!() }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
@@ -94,26 +72,14 @@ LL | fn bak() -> dyn Trait { unimplemented!() }
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the return type of a function must have a statically known size
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:16
-   |
-LL | fn bal() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-LL |     if true {
-LL |         return Struct;
-   |                ^^^^^^ expected trait `Trait`, found struct `Struct`
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                    found struct `Struct`
-
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:21:13
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
    |
 LL | fn bal() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
 help: if all the returned values were of the same type you could use `impl Trait` as the return type
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:5
    |
 LL |         return Struct;
    |                ^^^^^^
@@ -132,20 +98,8 @@ LL |     }
 LL |     Box::new(42)
    |
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5
-   |
-LL | fn bal() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-...
-LL |     42
-   |     ^^ expected trait `Trait`, found integer
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                      found type `{integer}`
-
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:13
+  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13
    |
 LL | fn bat() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
@@ -156,31 +110,7 @@ help: you can use the `impl Trait` feature in the return type because all the re
 LL | fn bat() -> impl Trait {
    |             ^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:31:16
-   |
-LL | fn bat() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-LL |     if true {
-LL |         return 0;
-   |                ^ expected trait `Trait`, found integer
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                      found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:33:5
-   |
-LL | fn bat() -> dyn Trait {
-   |             --------- expected `(dyn Trait + 'static)` because of return type
-...
-LL |     42
-   |     ^^ expected trait `Trait`, found integer
-   |
-   = note: expected trait object `(dyn Trait + 'static)`
-                      found type `{integer}`
-
-error: aborting due to 15 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.

From b4bbe784a9dc1f97f07e2543c6f726cb1eb4cc86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 16:13:51 -0800
Subject: [PATCH 05/25] Make `impl Trait` suggestion in E0746
 `MachineApplicable`

---
 src/librustc/traits/error_reporting.rs |  2 +-
 src/test/ui/error-codes/E0746.fixed    | 18 ++++++++++++++++++
 src/test/ui/error-codes/E0746.rs       |  2 ++
 src/test/ui/error-codes/E0746.stderr   |  4 ++--
 4 files changed, 23 insertions(+), 3 deletions(-)
 create mode 100644 src/test/ui/error-codes/E0746.fixed

diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 8f771658e4098..8d0923f571851 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1840,7 +1840,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 last_ty, trait_obj,
                             ),
                             format!("impl {}", trait_obj),
-                            Applicability::MaybeIncorrect,
+                            Applicability::MachineApplicable,
                         );
                         err.note(impl_trait_msg);
                     } else {
diff --git a/src/test/ui/error-codes/E0746.fixed b/src/test/ui/error-codes/E0746.fixed
new file mode 100644
index 0000000000000..ca8319aa020dc
--- /dev/null
+++ b/src/test/ui/error-codes/E0746.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+#![allow(dead_code)]
+struct Struct;
+trait Trait {}
+impl Trait for Struct {}
+impl Trait for u32 {}
+
+fn foo() -> impl Trait { Struct }
+//~^ ERROR E0746
+
+fn bar() -> impl Trait { //~ ERROR E0746
+    if true {
+        return 0;
+    }
+    42
+}
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0746.rs b/src/test/ui/error-codes/E0746.rs
index c9ab455a4c5b4..bf5ba8fff562a 100644
--- a/src/test/ui/error-codes/E0746.rs
+++ b/src/test/ui/error-codes/E0746.rs
@@ -1,3 +1,5 @@
+// run-rustfix
+#![allow(dead_code)]
 struct Struct;
 trait Trait {}
 impl Trait for Struct {}
diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr
index 44bd0d7ed7d37..0cffd108226d8 100644
--- a/src/test/ui/error-codes/E0746.stderr
+++ b/src/test/ui/error-codes/E0746.stderr
@@ -1,5 +1,5 @@
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/E0746.rs:6:13
+  --> $DIR/E0746.rs:8:13
    |
 LL | fn foo() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
@@ -11,7 +11,7 @@ LL | fn foo() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
 error[E0746]: return type cannot have a bare trait because it must be `Sized`
-  --> $DIR/E0746.rs:9:13
+  --> $DIR/E0746.rs:11:13
    |
 LL | fn bar() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time

From e1dd8a909531cd66080ca89227fb8828a01d7e22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 17:19:52 -0800
Subject: [PATCH 06/25] When trait bounds are missing for return values, point
 at them

---
 src/librustc/traits/error_reporting.rs        | 122 +++++++++++-------
 .../issue-64130-4-async-move.stderr           |  13 +-
 .../alloc-traits-no-impls-length-33.stderr    |  15 +++
 .../into-iter-no-impls-length-33.stderr       |  21 +++
 .../impl_bounds.stderr                        |   2 +-
 ...n-trait-return-should-be-impl-trait.stderr |   8 +-
 src/test/ui/issues/issue-58344.stderr         |   6 +
 src/test/ui/issues/issue-5883.stderr          |   3 +
 .../lifetime-elision-return-type-trait.stderr |   3 +
 .../feature-gate-never_type_fallback.stderr   |   4 +
 .../generic_underconstrained2.stderr          |   4 +
 11 files changed, 147 insertions(+), 54 deletions(-)

diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 8d0923f571851..d5af1a9a42dd7 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1130,6 +1130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
 
         self.note_obligation_cause(&mut err, obligation);
+        self.point_at_returns_when_relevant(&mut err, &obligation);
 
         err.emit();
     }
@@ -1737,35 +1738,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             // Recursively look for `TraitObject` types and if there's only one, use that span to
             // suggest `impl Trait`.
 
-            struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
-
-            impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
-                type Map = rustc::hir::map::Map<'v>;
-
-                fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
-                    hir::intravisit::NestedVisitorMap::None
-                }
-
-                fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-                    match ex.kind {
-                        hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
-                        _ => {}
-                    }
-                    hir::intravisit::walk_expr(self, ex);
-                }
-
-                fn visit_body(&mut self, body: &'v hir::Body<'v>) {
-                    if body.generator_kind().is_none() {
-                        if let hir::ExprKind::Block(block, None) = body.value.kind {
-                            if let Some(expr) = block.expr {
-                                self.0.push(expr);
-                            }
-                        }
-                    }
-                    hir::intravisit::walk_body(self, body);
-                }
-            }
-
             // Visit to make sure there's a single `return` type to suggest `impl Trait`,
             // otherwise suggest using `Box<dyn Trait>` or an enum.
             let mut visitor = ReturnsVisitor(vec![]);
@@ -1893,6 +1865,38 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         false
     }
 
+    fn point_at_returns_when_relevant(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
+        if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() {
+        } else {
+            return;
+        }
+
+        let hir = self.tcx.hir();
+        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let node = hir.find(parent_node);
+        if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
+            node
+        {
+            let body = hir.body(*body_id);
+            // Point at all the `return`s in the function as they have failed trait bounds.
+            let mut visitor = ReturnsVisitor(vec![]);
+            visitor.visit_body(&body);
+            let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+            for expr in &visitor.0 {
+                if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                    err.span_label(
+                        expr.span,
+                        &format!("this returned value is of type `{}`", returned_ty),
+                    );
+                }
+            }
+        }
+    }
+
     /// Given some node representing a fn-like thing in the HIR map,
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
@@ -2911,19 +2915,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
                 err.note(
-                    "the `Copy` trait is required because the \
-                          repeated element will be copied",
+                    "the `Copy` trait is required because the repeated element will be copied",
                 );
                 if suggest_const_in_array_repeat_expressions {
                     err.note(
                         "this array initializer can be evaluated at compile-time, for more \
-                              information, see issue \
-                              https://github.com/rust-lang/rust/issues/49147",
+                         information, see issue \
+                         https://github.com/rust-lang/rust/issues/49147",
                     );
                     if tcx.sess.opts.unstable_features.is_nightly_build() {
                         err.help(
                             "add `#![feature(const_in_array_repeat_expressions)]` to the \
-                                  crate attributes to enable",
+                             crate attributes to enable",
                         );
                     }
                 }
@@ -2941,16 +2944,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
             }
             ObligationCauseCode::SizedReturnType => {
-                err.note(
-                    "the return type of a function must have a \
-                          statically known size",
-                );
+                err.note("the return type of a function must have a statically known size");
             }
             ObligationCauseCode::SizedYieldType => {
-                err.note(
-                    "the yield type of a generator must have a \
-                          statically known size",
-                );
+                err.note("the yield type of a generator must have a statically known size");
             }
             ObligationCauseCode::AssignmentLhsSized => {
                 err.note("the left-hand-side of an assignment must have a statically known size");
@@ -2966,12 +2963,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     if last {
                         err.note(
                             "the last field of a packed struct may only have a \
-                                      dynamically sized type if it does not need drop to be run",
+                             dynamically sized type if it does not need drop to be run",
                         );
                     } else {
                         err.note(
-                            "only the last field of a struct may have a dynamically \
-                                      sized type",
+                            "only the last field of a struct may have a dynamically sized type",
                         );
                     }
                 }
@@ -3025,13 +3021,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             ObligationCauseCode::CompareImplMethodObligation { .. } => {
                 err.note(&format!(
                     "the requirement `{}` appears on the impl method \
-                              but not on the corresponding trait method",
+                     but not on the corresponding trait method",
                     predicate
                 ));
             }
             ObligationCauseCode::CompareImplTypeObligation { .. } => {
                 err.note(&format!(
-                    "the requirement `{}` appears on the associated impl type\
+                    "the requirement `{}` appears on the associated impl type \
                      but not on the corresponding associated trait type",
                     predicate
                 ));
@@ -3043,8 +3039,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 err.help("see issue #48214");
                 if tcx.sess.opts.unstable_features.is_nightly_build() {
                     err.help(
-                        "add `#![feature(trivial_bounds)]` to the \
-                              crate attributes to enable",
+                        "add `#![feature(trivial_bounds)]` to the crate attributes to enable",
                     );
                 }
             }
@@ -3186,3 +3181,32 @@ pub fn suggest_constraining_type_param(
     }
     false
 }
+
+struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
+
+impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
+    type Map = rustc::hir::map::Map<'v>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
+        hir::intravisit::NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+        match ex.kind {
+            hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
+            _ => {}
+        }
+        hir::intravisit::walk_expr(self, ex);
+    }
+
+    fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+        if body.generator_kind().is_none() {
+            if let hir::ExprKind::Block(block, None) = body.value.kind {
+                if let Some(expr) = block.expr {
+                    self.0.push(expr);
+                }
+            }
+        }
+        hir::intravisit::walk_body(self, body);
+    }
+}
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr
index 77d0885c38d58..f59dbc2638400 100644
--- a/src/test/ui/async-await/issue-64130-4-async-move.stderr
+++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr
@@ -1,8 +1,17 @@
 error: future cannot be sent between threads safely
   --> $DIR/issue-64130-4-async-move.rs:15:17
    |
-LL | pub fn foo() -> impl Future + Send {
-   |                 ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+LL |   pub fn foo() -> impl Future + Send {
+   |                   ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+...
+LL | /     async move {
+LL | |         match client.status() {
+LL | |             200 => {
+LL | |                 let _x = get().await;
+...  |
+LL | |         }
+LL | |     }
+   | |_____- this returned value is of type `impl std::future::Future`
    |
    = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
 note: future is not `Send` as this value is used across an await
diff --git a/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr
index 5c37468130c64..6e5afcdb8bb68 100644
--- a/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/alloc-traits-no-impls-length-33.stderr
@@ -3,6 +3,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+...
+LL |     Vec::<A>::new()
+   |     --------------- this returned value is of type `std::vec::Vec<A>`
    |
    = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec<A>`
    = note: the return type of a function must have a statically known size
@@ -12,6 +15,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+...
+LL |     Vec::<A>::new()
+   |     --------------- this returned value is of type `std::vec::Vec<A>`
    |
    = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec<A>`
    = note: the return type of a function must have a statically known size
@@ -21,6 +27,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
    |                                                ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+...
+LL |     VecDeque::<A>::new()
+   |     -------------------- this returned value is of type `std::collections::VecDeque<A>`
    |
    = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque<A>`
    = note: the return type of a function must have a statically known size
@@ -30,6 +39,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+...
+LL |     VecDeque::<A>::new()
+   |     -------------------- this returned value is of type `std::collections::VecDeque<A>`
    |
    = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque<A>`
    = note: the return type of a function must have a statically known size
@@ -39,6 +51,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
    |                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+...
+LL |     VecDeque::<A>::new()
+   |     -------------------- this returned value is of type `std::collections::VecDeque<A>`
    |
    = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque<A>`
    = note: the return type of a function must have a statically known size
diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
index bfdff8e3bbe61..e615e10bd5f5f 100644
--- a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
@@ -11,6 +11,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -28,6 +31,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -45,6 +51,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -62,6 +71,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_fused_iterator() -> impl FusedIterator {
    |                               ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -79,6 +91,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_trusted_len() -> impl TrustedLen {
    |                            ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -96,6 +111,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_clone() -> impl Clone {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -113,6 +131,9 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32
    |
 LL | pub fn no_debug() -> impl Debug {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
+LL |
+LL |     IntoIter::new([0i32; 33])
+   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
    |
    = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr
index 017990076931b..ca2350ff7577f 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.stderr
+++ b/src/test/ui/generic-associated-types/impl_bounds.stderr
@@ -38,7 +38,7 @@ LL |     type C where Self: Copy = String;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
    = note: required because of the requirements on the impl of `std::marker::Copy` for `Fooy<T>`
-   = note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl typebut not on the corresponding associated trait type
+   = note: the requirement `Fooy<T>: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index a09ce2bb29863..d51cd6aeae6ec 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -11,7 +11,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
    |
 LL | fn fuz() -> (usize, Trait) { (42, Struct) }
-   |             ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |             ^^^^^^^^^^^^^^   ------------ this returned value is of type `(usize, (dyn Trait + 'static))`
+   |             |
+   |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
@@ -31,7 +33,9 @@ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be know
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
    |
 LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
-   |             ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |             ^^^^^^^^^^^^^^^^^^   ------------ this returned value is of type `(usize, (dyn Trait + 'static))`
+   |             |
+   |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr
index 427d03b679d5f..9b07dbd7ab69c 100644
--- a/src/test/ui/issues/issue-58344.stderr
+++ b/src/test/ui/issues/issue-58344.stderr
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait
    |
 LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
+...
+LL |     add_generic(value, 1u32)
+   |     ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>`
    |
    = note: the return type of a function must have a statically known size
 
@@ -11,6 +14,9 @@ error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait
    |
 LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
+...
+LL |     add_generic(value, 1u32)
+   |     ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>`
    |
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr
index c2de1d095505a..d886ecc11d17b 100644
--- a/src/test/ui/issues/issue-5883.stderr
+++ b/src/test/ui/issues/issue-5883.stderr
@@ -14,6 +14,9 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at
    |
 LL |     -> Struct {
    |        ^^^^^^ doesn't have a size known at compile-time
+LL |
+LL |     Struct { r: r }
+   |     --------------- this returned value is of type `Struct`
    |
    = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index 228582d0001da..49fa11c35aef8 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf
    |
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
+LL |
+LL |     Ok(())
+   |     ------ this returned value is of type `std::result::Result<_, _>`
    |
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
index 837e90d6ceb9b..88bfed2b54742 100644
--- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -3,8 +3,12 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^ the trait `T` is not implemented for `()`
+LL |
+LL |     panic!()
+   |     -------- this returned value is of type `_`
    |
    = note: the return type of a function must have a statically known size
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index d4c7c7c74529e..9e8414f9c15fe 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -18,6 +18,8 @@ LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
 ...
 LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
    |                     - help: consider restricting this bound: `U: std::fmt::Debug`
+LL |     5u32
+   |     ---- this returned value is of type `u32`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `U`
    = note: the return type of a function must have a statically known size
@@ -30,6 +32,8 @@ LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
 ...
 LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
    |                         - help: consider restricting this bound: `V: std::fmt::Debug`
+LL |     5u32
+   |     ---- this returned value is of type `u32`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `V`
    = note: the return type of a function must have a statically known size

From 93293c56e85a2afdde8664bc08303d5f5853ba29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 17:20:28 -0800
Subject: [PATCH 07/25] fmt

---
 src/librustc/traits/error_reporting.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index d5af1a9a42dd7..77a73aba45484 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -3038,9 +3038,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             ObligationCauseCode::TrivialBound => {
                 err.help("see issue #48214");
                 if tcx.sess.opts.unstable_features.is_nightly_build() {
-                    err.help(
-                        "add `#![feature(trivial_bounds)]` to the crate attributes to enable",
-                    );
+                    err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
                 }
             }
             ObligationCauseCode::AssocTypeBound(ref data) => {

From 4c13d2555c4535516eb00dd0221c9d158b91e31c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 17:21:31 -0800
Subject: [PATCH 08/25] Add E0746 explanation to the index

---
 src/librustc_error_codes/error_codes.rs       |   2 +-
 src/librustc_error_codes/error_codes/E0746.md | 137 ++++++++++++++++++
 src/test/ui/error-codes/E0746.stderr          |   1 +
 ...n-trait-return-should-be-impl-trait.stderr |   2 +-
 4 files changed, 140 insertions(+), 2 deletions(-)
 create mode 100644 src/librustc_error_codes/error_codes/E0746.md

diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index c17cb7dd9f161..180ccb15977dd 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -414,6 +414,7 @@ E0742: include_str!("./error_codes/E0742.md"),
 E0743: include_str!("./error_codes/E0743.md"),
 E0744: include_str!("./error_codes/E0744.md"),
 E0745: include_str!("./error_codes/E0745.md"),
+E0746: include_str!("./error_codes/E0746.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
@@ -608,5 +609,4 @@ E0745: include_str!("./error_codes/E0745.md"),
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
     E0727, // `async` generators are not yet supported
     E0739, // invalid track_caller application/syntax
-    E0746, // `dyn Trait` return type
 }
diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md
new file mode 100644
index 0000000000000..538c9d720d71b
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0746.md
@@ -0,0 +1,137 @@
+Return types cannot be `dyn Trait`s as they must be `Sized`.
+
+Erroneous code example:
+
+```compile_fail,E0746
+trait T {
+    fn bar(&self);
+}
+struct S(usize);
+impl T for S {
+    fn bar(&self) {}
+}
+
+// Having the trait `T` as return type is invalid because bare traits do not
+have a statically known size:
+fn foo() -> dyn T {
+    S(42)
+}
+```
+
+To avoid the error there are a couple of options.
+
+If there is a single type involved, you can use [`impl Trait`]:
+
+```
+# trait T {
+#     fn bar(&self);
+# }
+# struct S(usize);
+# impl T for S {
+#     fn bar(&self) {}
+# }
+// The compiler will select `S(usize)` as the materialized return type of this
+// function, but callers will only be able to access associated items from `T`.
+fn foo() -> impl T {
+    S(42)
+}
+```
+
+If there are multiple types involved, the only way you care to interact with
+them is through the trait's interface and having to rely on dynamic dispatch is
+acceptable, then you can use [trait objects] with `Box`, or other container
+types like `Rc` or `Arc`:
+
+```
+# trait T {
+#     fn bar(&self);
+# }
+# struct S(usize);
+# impl T for S {
+#     fn bar(&self) {}
+# }
+struct O(&'static str);
+impl T for O {
+    fn bar(&self) {}
+}
+
+// This now returns a "trait object" and callers are only be able to access
+// associated items from `T`.
+fn foo(x: bool) -> Box<dyn T> {
+    if x {
+        Box::new(S(42))
+    } else {
+        Box::new(O("val"))
+    }
+}
+```
+
+Finally, if you wish to still be able to access the original type, you can
+create a new `enum` with a variant for each type:
+
+```
+# trait T {
+#     fn bar(&self);
+# }
+# struct S(usize);
+# impl T for S {
+#     fn bar(&self) {}
+# }
+# struct O(&'static str);
+# impl T for O {
+#     fn bar(&self) {}
+# }
+enum E {
+    S(S),
+    O(O),
+}
+
+// The caller can access the original types directly, but it needs to match on
+// the returned `enum E`.
+fn foo(x: bool) -> E {
+    if x {
+        E::S(S(42))
+    } else {
+        E::O(O("val"))
+    }
+}
+```
+
+You can even implement the `trait` on the returned `enum` so the callers
+*don't* have to match on the returned value to invoke the associated items:
+
+```
+# trait T {
+#     fn bar(&self);
+# }
+# struct S(usize);
+# impl T for S {
+#     fn bar(&self) {}
+# }
+# struct O(&'static str);
+# impl T for O {
+#     fn bar(&self) {}
+# }
+# enum E {
+#     S(S),
+#     O(O),
+# }
+impl T for E {
+    fn bar(&self) {
+        match self {
+            E::S(s) => s.bar(),
+            E::O(o) => o.bar(),
+        }
+    }
+}
+```
+
+If you decide to use trait objects, be aware that these rely on
+[dynamic dispatch], which has performance implications, as the compiler needs
+to emit code that will figure out which method to call *at runtime* instead of
+during compilation. Using trait objects we are trading flexibility for
+performance.
+
+[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
+[trait objects]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
+[dynamic dispatch]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch
diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr
index 0cffd108226d8..1c88ce64749ae 100644
--- a/src/test/ui/error-codes/E0746.stderr
+++ b/src/test/ui/error-codes/E0746.stderr
@@ -24,3 +24,4 @@ LL | fn bar() -> impl Trait {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0746`.
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index d51cd6aeae6ec..ff7438e9affc1 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -116,5 +116,5 @@ LL | fn bat() -> impl Trait {
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0277, E0308.
+Some errors have detailed explanations: E0277, E0308, E0746.
 For more information about an error, try `rustc --explain E0277`.

From 9dee5d582f538e1d12f278e23ee47cb7c201c9b7 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 3 Jan 2020 13:31:56 +0100
Subject: [PATCH 09/25] fix rustfmt fallout

---
 src/librustc/mir/interpret/error.rs        |  5 +++--
 src/librustc/mir/interpret/mod.rs          |  4 ++--
 src/librustc_mir/interpret/cast.rs         | 20 +++++++++++---------
 src/librustc_mir/interpret/eval_context.rs | 12 +++++++++---
 src/librustc_mir/interpret/memory.rs       |  4 ++--
 src/librustc_mir/interpret/operand.rs      | 22 +++++++++++-----------
 src/librustc_mir/interpret/place.rs        | 11 +++++------
 src/librustc_mir/interpret/validity.rs     | 10 +++++-----
 8 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 8643bd63d8cba..29b3b045ca5fe 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -33,7 +33,7 @@ impl ErrorHandled {
             ErrorHandled::Reported => {}
             ErrorHandled::TooGeneric => bug!(
                 "MIR interpretation failed without reporting an error \
-                                              even though it was fully monomorphized"
+                 even though it was fully monomorphized"
             ),
         }
     }
@@ -137,7 +137,8 @@ impl<'tcx> ConstEvalErr<'tcx> {
     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
         let must_error = match self.error {
             InterpError::MachineStop(_) => bug!("CTFE does not stop"),
-            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+            err_inval!(Layout(LayoutError::Unknown(_)))
+            | err_inval!(TooGeneric) => {
                 return Err(ErrorHandled::TooGeneric);
             }
             err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 47f067590b9d5..e554b280ef78c 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -403,8 +403,8 @@ impl<'tcx> AllocMap<'tcx> {
         let next = self.next_id;
         self.next_id.0 = self.next_id.0.checked_add(1).expect(
             "You overflowed a u64 by incrementing by 1... \
-                     You've just earned yourself a free drink if we ever meet. \
-                     Seriously, how did you do that?!",
+             You've just earned yourself a free drink if we ever meet. \
+             Seriously, how did you do that?!",
         );
         next
     }
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 9461a06690212..6d0b6bf70ad8c 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -118,15 +118,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
             // are represented as integers.
-            _ => assert!(
-                src.layout.ty.is_bool()
-                    || src.layout.ty.is_char()
-                    || src.layout.ty.is_enum()
-                    || src.layout.ty.is_integral()
-                    || src.layout.ty.is_any_ptr(),
-                "Unexpected cast from type {:?}",
-                src.layout.ty
-            ),
+            _ => {
+                assert!(
+                    src.layout.ty.is_bool()
+                        || src.layout.ty.is_char()
+                        || src.layout.ty.is_enum()
+                        || src.layout.ty.is_integral()
+                        || src.layout.ty.is_any_ptr(),
+                    "Unexpected cast from type {:?}",
+                    src.layout.ty
+                )
+            }
         }
 
         // Handle cast from a univariant (ZST) enum.
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 206d3d156735e..3d590fb820359 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -152,10 +152,16 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
         &mut self,
     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
         match self.value {
-            LocalValue::Dead => throw_unsup!(DeadLocal),
-            LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
+            LocalValue::Dead => {
+                throw_unsup!(DeadLocal)
+            }
+            LocalValue::Live(Operand::Indirect(mplace)) => {
+                Ok(Err(mplace))
+            }
             ref mut local @ LocalValue::Live(Operand::Immediate(_))
-            | ref mut local @ LocalValue::Uninitialized => Ok(Ok(local)),
+            | ref mut local @ LocalValue::Uninitialized => {
+                Ok(Ok(local))
+            }
         }
     }
 }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index cb676821fd438..3386254c93b75 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -581,9 +581,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 Ok((layout.size, layout.align.abi))
             }
             Some(GlobalAlloc::Memory(alloc)) =>
-            // Need to duplicate the logic here, because the global allocations have
-            // different associated types than the interpreter-local ones.
             {
+                // Need to duplicate the logic here, because the global allocations have
+                // different associated types than the interpreter-local ones.
                 Ok((alloc.size, alloc.align))
             }
             Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index b37eff3f40626..34a32daaab65f 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -543,7 +543,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | ty::ConstKind::Placeholder(..) => {
                 bug!("eval_const_to_op: Unexpected ConstKind {:?}", val)
             }
-            ty::ConstKind::Value(val_val) => val_val,
+            ty::ConstKind::Value(val_val) => {
+                val_val
+            }
         };
         // Other cases need layout.
         let layout = from_known_layout(layout, || self.layout_of(val.ty))?;
@@ -684,16 +686,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             let variant_index = variants_start
                                 .checked_add(variant_index_relative)
                                 .expect("oveflow computing absolute variant idx");
-                            assert!(
-                                (variant_index as usize)
-                                    < rval
-                                        .layout
-                                        .ty
-                                        .ty_adt_def()
-                                        .expect("tagged layout for non adt")
-                                        .variants
-                                        .len()
-                            );
+                            let variants_len = rval
+                                .layout
+                                .ty
+                                .ty_adt_def()
+                                .expect("tagged layout for non adt")
+                                .variants
+                                .len();
+                            assert!((variant_index as usize) < variants_len);
                             (u128::from(variant_index), VariantIdx::from_u32(variant_index))
                         } else {
                             (u128::from(dataful_variant.as_u32()), dataful_variant)
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 8888e3fd4632a..4f96cb698915d 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -432,12 +432,11 @@ where
             // happens at run-time so that's okay.
             let align = match self.size_and_align_of(base.meta, field_layout)? {
                 Some((_, align)) => align,
-                None if offset == Size::ZERO =>
-                // An extern type at offset 0, we fall back to its static alignment.
-                // FIXME: Once we have made decisions for how to handle size and alignment
-                // of `extern type`, this should be adapted.  It is just a temporary hack
-                // to get some code to work that probably ought to work.
-                {
+                None if offset == Size::ZERO => {
+                    // An extern type at offset 0, we fall back to its static alignment.
+                    // FIXME: Once we have made decisions for how to handle size and alignment
+                    // of `extern type`, this should be adapted.  It is just a temporary hack
+                    // to get some code to work that probably ought to work.
                     field_layout.align.abi
                 }
                 None => bug!("Cannot compute offset for extern type field at non-0 offset"),
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 2f0fb81fffd13..d0fef08bb60c7 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -115,11 +115,11 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
             TupleElem(idx) => write!(out, ".{}", idx),
             ArrayElem(idx) => write!(out, "[{}]", idx),
             Deref =>
-            // This does not match Rust syntax, but it is more readable for long paths -- and
-            // some of the other items here also are not Rust syntax.  Actually we can't
-            // even use the usual syntax because we are just showing the projections,
-            // not the root.
             {
+                // This does not match Rust syntax, but it is more readable for long paths -- and
+                // some of the other items here also are not Rust syntax.  Actually we can't
+                // even use the usual syntax because we are just showing the projections,
+                // not the root.
                 write!(out, ".<deref>")
             }
             Tag => write!(out, ".<enum-tag>"),
@@ -207,8 +207,8 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
                 // we might be projecting *to* a variant, or to a field *in*a variant.
                 match layout.variants {
                     layout::Variants::Single { index } =>
-                    // Inside a variant
                     {
+                        // Inside a variant
                         PathElem::Field(def.variants[index].fields[field].ident.name)
                     }
                     _ => bug!(),

From 00c82726122d550c586e11bf85501a93ce0fbf75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 13 Jan 2020 18:27:42 -0800
Subject: [PATCH 10/25] Split `librustc/traits/error_reporting.rs`

---
 src/librustc/traits/error_reporting/mod.rs    | 1442 +++++++++++++++
 .../error_reporting/on_unimplemented.rs       |  199 +++
 .../suggestions.rs}                           | 1557 +----------------
 3 files changed, 1667 insertions(+), 1531 deletions(-)
 create mode 100644 src/librustc/traits/error_reporting/mod.rs
 create mode 100644 src/librustc/traits/error_reporting/on_unimplemented.rs
 rename src/librustc/traits/{error_reporting.rs => error_reporting/suggestions.rs} (52%)

diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs
new file mode 100644
index 0000000000000..f8329124851b0
--- /dev/null
+++ b/src/librustc/traits/error_reporting/mod.rs
@@ -0,0 +1,1442 @@
+pub mod on_unimplemented;
+pub mod suggestions;
+
+use super::{
+    ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode,
+    MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause,
+    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote,
+    OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError,
+    TraitNotObjectSafe,
+};
+
+use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{self, InferCtxt};
+use crate::mir::interpret::ErrorHandled;
+use crate::session::DiagnosticMessageId;
+use crate::traits::object_safety_violations;
+use crate::ty::error::ExpectedFound;
+use crate::ty::fast_reject;
+use crate::ty::fold::TypeFolder;
+use crate::ty::SubtypePredicate;
+use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use std::fmt;
+use syntax::ast;
+
+use rustc_error_codes::*;
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    pub fn report_fulfillment_errors(
+        &self,
+        errors: &[FulfillmentError<'tcx>],
+        body_id: Option<hir::BodyId>,
+        fallback_has_occurred: bool,
+    ) {
+        #[derive(Debug)]
+        struct ErrorDescriptor<'tcx> {
+            predicate: ty::Predicate<'tcx>,
+            index: Option<usize>, // None if this is an old error
+        }
+
+        let mut error_map: FxHashMap<_, Vec<_>> = self
+            .reported_trait_errors
+            .borrow()
+            .iter()
+            .map(|(&span, predicates)| {
+                (
+                    span,
+                    predicates
+                        .iter()
+                        .map(|predicate| ErrorDescriptor {
+                            predicate: predicate.clone(),
+                            index: None,
+                        })
+                        .collect(),
+                )
+            })
+            .collect();
+
+        for (index, error) in errors.iter().enumerate() {
+            // We want to ignore desugarings here: spans are equivalent even
+            // if one is the result of a desugaring and the other is not.
+            let mut span = error.obligation.cause.span;
+            let expn_data = span.ctxt().outer_expn_data();
+            if let ExpnKind::Desugaring(_) = expn_data.kind {
+                span = expn_data.call_site;
+            }
+
+            error_map.entry(span).or_default().push(ErrorDescriptor {
+                predicate: error.obligation.predicate.clone(),
+                index: Some(index),
+            });
+
+            self.reported_trait_errors
+                .borrow_mut()
+                .entry(span)
+                .or_default()
+                .push(error.obligation.predicate.clone());
+        }
+
+        // We do this in 2 passes because we want to display errors in order, though
+        // maybe it *is* better to sort errors by span or something.
+        let mut is_suppressed = vec![false; errors.len()];
+        for (_, error_set) in error_map.iter() {
+            // We want to suppress "duplicate" errors with the same span.
+            for error in error_set {
+                if let Some(index) = error.index {
+                    // Suppress errors that are either:
+                    // 1) strictly implied by another error.
+                    // 2) implied by an error with a smaller index.
+                    for error2 in error_set {
+                        if error2.index.map_or(false, |index2| is_suppressed[index2]) {
+                            // Avoid errors being suppressed by already-suppressed
+                            // errors, to prevent all errors from being suppressed
+                            // at once.
+                            continue;
+                        }
+
+                        if self.error_implies(&error2.predicate, &error.predicate)
+                            && !(error2.index >= error.index
+                                && self.error_implies(&error.predicate, &error2.predicate))
+                        {
+                            info!("skipping {:?} (implied by {:?})", error, error2);
+                            is_suppressed[index] = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        for (error, suppressed) in errors.iter().zip(is_suppressed) {
+            if !suppressed {
+                self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+            }
+        }
+    }
+
+    // returns if `cond` not occurring implies that `error` does not occur - i.e., that
+    // `error` occurring implies that `cond` occurs.
+    fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool {
+        if cond == error {
+            return true;
+        }
+
+        let (cond, error) = match (cond, error) {
+            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error),
+            _ => {
+                // FIXME: make this work in other cases too.
+                return false;
+            }
+        };
+
+        for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
+            if let ty::Predicate::Trait(implication) = implication {
+                let error = error.to_poly_trait_ref();
+                let implication = implication.to_poly_trait_ref();
+                // FIXME: I'm just not taking associated types at all here.
+                // Eventually I'll need to implement param-env-aware
+                // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
+                let param_env = ty::ParamEnv::empty();
+                if self.can_sub(param_env, error, implication).is_ok() {
+                    debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
+                    return true;
+                }
+            }
+        }
+
+        false
+    }
+
+    fn report_fulfillment_error(
+        &self,
+        error: &FulfillmentError<'tcx>,
+        body_id: Option<hir::BodyId>,
+        fallback_has_occurred: bool,
+    ) {
+        debug!("report_fulfillment_error({:?})", error);
+        match error.code {
+            FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
+                self.report_selection_error(
+                    &error.obligation,
+                    selection_error,
+                    fallback_has_occurred,
+                    error.points_at_arg_span,
+                );
+            }
+            FulfillmentErrorCode::CodeProjectionError(ref e) => {
+                self.report_projection_error(&error.obligation, e);
+            }
+            FulfillmentErrorCode::CodeAmbiguity => {
+                self.maybe_report_ambiguity(&error.obligation, body_id);
+            }
+            FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
+                self.report_mismatched_types(
+                    &error.obligation.cause,
+                    expected_found.expected,
+                    expected_found.found,
+                    err.clone(),
+                )
+                .emit();
+            }
+        }
+    }
+
+    fn report_projection_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        error: &MismatchedProjectionTypes<'tcx>,
+    ) {
+        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+
+        if predicate.references_error() {
+            return;
+        }
+
+        self.probe(|_| {
+            let err_buf;
+            let mut err = &error.err;
+            let mut values = None;
+
+            // try to find the mismatched types to report the error with.
+            //
+            // this can fail if the problem was higher-ranked, in which
+            // cause I have no idea for a good error message.
+            if let ty::Predicate::Projection(ref data) = predicate {
+                let mut selcx = SelectionContext::new(self);
+                let (data, _) = self.replace_bound_vars_with_fresh_vars(
+                    obligation.cause.span,
+                    infer::LateBoundRegionConversionTime::HigherRankedType,
+                    data,
+                );
+                let mut obligations = vec![];
+                let normalized_ty = super::normalize_projection_type(
+                    &mut selcx,
+                    obligation.param_env,
+                    data.projection_ty,
+                    obligation.cause.clone(),
+                    0,
+                    &mut obligations,
+                );
+
+                debug!(
+                    "report_projection_error obligation.cause={:?} obligation.param_env={:?}",
+                    obligation.cause, obligation.param_env
+                );
+
+                debug!(
+                    "report_projection_error normalized_ty={:?} data.ty={:?}",
+                    normalized_ty, data.ty
+                );
+
+                let is_normalized_ty_expected = match &obligation.cause.code {
+                    ObligationCauseCode::ItemObligation(_)
+                    | ObligationCauseCode::BindingObligation(_, _)
+                    | ObligationCauseCode::ObjectCastObligation(_) => false,
+                    _ => true,
+                };
+
+                if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
+                    is_normalized_ty_expected,
+                    normalized_ty,
+                    data.ty,
+                ) {
+                    values = Some(infer::ValuePairs::Types(ExpectedFound::new(
+                        is_normalized_ty_expected,
+                        normalized_ty,
+                        data.ty,
+                    )));
+
+                    err_buf = error;
+                    err = &err_buf;
+                }
+            }
+
+            let msg = format!("type mismatch resolving `{}`", predicate);
+            let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg);
+            let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+            if fresh {
+                let mut diag = struct_span_err!(
+                    self.tcx.sess,
+                    obligation.cause.span,
+                    E0271,
+                    "type mismatch resolving `{}`",
+                    predicate
+                );
+                self.note_type_err(&mut diag, &obligation.cause, None, values, err);
+                self.note_obligation_cause(&mut diag, obligation);
+                diag.emit();
+            }
+        });
+    }
+
+    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+        /// returns the fuzzy category of a given type, or None
+        /// if the type can be equated to any type.
+        fn type_category(t: Ty<'_>) -> Option<u32> {
+            match t.kind {
+                ty::Bool => Some(0),
+                ty::Char => Some(1),
+                ty::Str => Some(2),
+                ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
+                ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
+                ty::Ref(..) | ty::RawPtr(..) => Some(5),
+                ty::Array(..) | ty::Slice(..) => Some(6),
+                ty::FnDef(..) | ty::FnPtr(..) => Some(7),
+                ty::Dynamic(..) => Some(8),
+                ty::Closure(..) => Some(9),
+                ty::Tuple(..) => Some(10),
+                ty::Projection(..) => Some(11),
+                ty::Param(..) => Some(12),
+                ty::Opaque(..) => Some(13),
+                ty::Never => Some(14),
+                ty::Adt(adt, ..) => match adt.adt_kind() {
+                    AdtKind::Struct => Some(15),
+                    AdtKind::Union => Some(16),
+                    AdtKind::Enum => Some(17),
+                },
+                ty::Generator(..) => Some(18),
+                ty::Foreign(..) => Some(19),
+                ty::GeneratorWitness(..) => Some(20),
+                ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
+                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+            }
+        }
+
+        match (type_category(a), type_category(b)) {
+            (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) {
+                (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
+                _ => cat_a == cat_b,
+            },
+            // infer and error can be equated to all types
+            _ => true,
+        }
+    }
+
+    fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
+        self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind {
+            hir::GeneratorKind::Gen => "a generator",
+            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
+            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
+            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
+        })
+    }
+
+    fn find_similar_impl_candidates(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Vec<ty::TraitRef<'tcx>> {
+        let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true);
+        let all_impls = self.tcx.all_impls(trait_ref.def_id());
+
+        match simp {
+            Some(simp) => all_impls
+                .iter()
+                .filter_map(|&def_id| {
+                    let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+                    let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
+                    if let Some(imp_simp) = imp_simp {
+                        if simp != imp_simp {
+                            return None;
+                        }
+                    }
+
+                    Some(imp)
+                })
+                .collect(),
+            None => {
+                all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect()
+            }
+        }
+    }
+
+    fn report_similar_impl_candidates(
+        &self,
+        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if impl_candidates.is_empty() {
+            return;
+        }
+
+        let len = impl_candidates.len();
+        let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 };
+
+        let normalize = |candidate| {
+            self.tcx.infer_ctxt().enter(|ref infcx| {
+                let normalized = infcx
+                    .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+                    .normalize(candidate)
+                    .ok();
+                match normalized {
+                    Some(normalized) => format!("\n  {:?}", normalized.value),
+                    None => format!("\n  {:?}", candidate),
+                }
+            })
+        };
+
+        // Sort impl candidates so that ordering is consistent for UI tests.
+        let mut normalized_impl_candidates =
+            impl_candidates.iter().map(normalize).collect::<Vec<String>>();
+
+        // Sort before taking the `..end` range,
+        // because the ordering of `impl_candidates` may not be deterministic:
+        // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
+        normalized_impl_candidates.sort();
+
+        err.help(&format!(
+            "the following implementations were found:{}{}",
+            normalized_impl_candidates[..end].join(""),
+            if len > 5 { format!("\nand {} others", len - 4) } else { String::new() }
+        ));
+    }
+
+    /// Reports that an overflow has occurred and halts compilation. We
+    /// halt compilation unconditionally because it is important that
+    /// overflows never be masked -- they basically represent computations
+    /// whose result could not be truly determined and thus we can't say
+    /// if the program type checks or not -- and they are unusual
+    /// occurrences in any case.
+    pub fn report_overflow_error<T>(
+        &self,
+        obligation: &Obligation<'tcx, T>,
+        suggest_increasing_limit: bool,
+    ) -> !
+    where
+        T: fmt::Display + TypeFoldable<'tcx>,
+    {
+        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            obligation.cause.span,
+            E0275,
+            "overflow evaluating the requirement `{}`",
+            predicate
+        );
+
+        if suggest_increasing_limit {
+            self.suggest_new_overflow_limit(&mut err);
+        }
+
+        self.note_obligation_cause_code(
+            &mut err,
+            &obligation.predicate,
+            &obligation.cause.code,
+            &mut vec![],
+        );
+
+        err.emit();
+        self.tcx.sess.abort_if_errors();
+        bug!();
+    }
+
+    /// Reports that a cycle was detected which led to overflow and halts
+    /// compilation. This is equivalent to `report_overflow_error` except
+    /// that we can give a more helpful error message (and, in particular,
+    /// we do not suggest increasing the overflow limit, which is not
+    /// going to help).
+    pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+        let cycle = self.resolve_vars_if_possible(&cycle.to_owned());
+        assert!(cycle.len() > 0);
+
+        debug!("report_overflow_error_cycle: cycle={:?}", cycle);
+
+        self.report_overflow_error(&cycle[0], false);
+    }
+
+    pub fn report_extra_impl_obligation(
+        &self,
+        error_span: Span,
+        item_name: ast::Name,
+        _impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+        requirement: &dyn fmt::Display,
+    ) -> DiagnosticBuilder<'tcx> {
+        let msg = "impl has stricter requirements than trait";
+        let sp = self.tcx.sess.source_map().def_span(error_span);
+
+        let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
+
+        if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
+            let span = self.tcx.sess.source_map().def_span(trait_item_span);
+            err.span_label(span, format!("definition of `{}` from trait", item_name));
+        }
+
+        err.span_label(sp, format!("impl has extra requirement {}", requirement));
+
+        err
+    }
+
+    /// Gets the parent trait chain start
+    fn get_parent_trait_ref(
+        &self,
+        code: &ObligationCauseCode<'tcx>,
+    ) -> Option<(String, Option<Span>)> {
+        match code {
+            &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+                match self.get_parent_trait_ref(&data.parent_code) {
+                    Some(t) => Some(t),
+                    None => {
+                        let ty = parent_trait_ref.skip_binder().self_ty();
+                        let span =
+                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+                        Some((ty.to_string(), span))
+                    }
+                }
+            }
+            _ => None,
+        }
+    }
+
+    pub fn report_selection_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        error: &SelectionError<'tcx>,
+        fallback_has_occurred: bool,
+        points_at_arg: bool,
+    ) {
+        let tcx = self.tcx;
+        let span = obligation.cause.span;
+
+        let mut err = match *error {
+            SelectionError::Unimplemented => {
+                if let ObligationCauseCode::CompareImplMethodObligation {
+                    item_name,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                }
+                | ObligationCauseCode::CompareImplTypeObligation {
+                    item_name,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                } = obligation.cause.code
+                {
+                    self.report_extra_impl_obligation(
+                        span,
+                        item_name,
+                        impl_item_def_id,
+                        trait_item_def_id,
+                        &format!("`{}`", obligation.predicate),
+                    )
+                    .emit();
+                    return;
+                }
+                match obligation.predicate {
+                    ty::Predicate::Trait(ref trait_predicate) => {
+                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+
+                        if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+                            return;
+                        }
+                        let trait_ref = trait_predicate.to_poly_trait_ref();
+                        let (post_message, pre_message, type_def) = self
+                            .get_parent_trait_ref(&obligation.cause.code)
+                            .map(|(t, s)| {
+                                (
+                                    format!(" in `{}`", t),
+                                    format!("within `{}`, ", t),
+                                    s.map(|s| (format!("within this `{}`", t), s)),
+                                )
+                            })
+                            .unwrap_or_default();
+
+                        let OnUnimplementedNote { message, label, note, enclosing_scope } =
+                            self.on_unimplemented_note(trait_ref, obligation);
+                        let have_alt_message = message.is_some() || label.is_some();
+                        let is_try = self
+                            .tcx
+                            .sess
+                            .source_map()
+                            .span_to_snippet(span)
+                            .map(|s| &s == "?")
+                            .unwrap_or(false);
+                        let is_from = format!("{}", trait_ref.print_only_trait_path())
+                            .starts_with("std::convert::From<");
+                        let (message, note) = if is_try && is_from {
+                            (
+                                Some(format!(
+                                    "`?` couldn't convert the error to `{}`",
+                                    trait_ref.self_ty(),
+                                )),
+                                Some(
+                                    "the question mark operation (`?`) implicitly performs a \
+                                     conversion on the error value using the `From` trait"
+                                        .to_owned(),
+                                ),
+                            )
+                        } else {
+                            (message, note)
+                        };
+
+                        let mut err = struct_span_err!(
+                            self.tcx.sess,
+                            span,
+                            E0277,
+                            "{}",
+                            message.unwrap_or_else(|| format!(
+                                "the trait bound `{}` is not satisfied{}",
+                                trait_ref.to_predicate(),
+                                post_message,
+                            ))
+                        );
+
+                        let explanation =
+                            if obligation.cause.code == ObligationCauseCode::MainFunctionType {
+                                "consider using `()`, or a `Result`".to_owned()
+                            } else {
+                                format!(
+                                    "{}the trait `{}` is not implemented for `{}`",
+                                    pre_message,
+                                    trait_ref.print_only_trait_path(),
+                                    trait_ref.self_ty(),
+                                )
+                            };
+
+                        if self.suggest_add_reference_to_arg(
+                            &obligation,
+                            &mut err,
+                            &trait_ref,
+                            points_at_arg,
+                            have_alt_message,
+                        ) {
+                            self.note_obligation_cause(&mut err, obligation);
+                            err.emit();
+                            return;
+                        }
+                        if let Some(ref s) = label {
+                            // If it has a custom `#[rustc_on_unimplemented]`
+                            // error message, let's display it as the label!
+                            err.span_label(span, s.as_str());
+                            err.help(&explanation);
+                        } else {
+                            err.span_label(span, explanation);
+                        }
+                        if let Some((msg, span)) = type_def {
+                            err.span_label(span, &msg);
+                        }
+                        if let Some(ref s) = note {
+                            // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
+                            err.note(s.as_str());
+                        }
+                        if let Some(ref s) = enclosing_scope {
+                            let enclosing_scope_span = tcx.def_span(
+                                tcx.hir()
+                                    .opt_local_def_id(obligation.cause.body_id)
+                                    .unwrap_or_else(|| {
+                                        tcx.hir().body_owner_def_id(hir::BodyId {
+                                            hir_id: obligation.cause.body_id,
+                                        })
+                                    }),
+                            );
+
+                            err.span_label(enclosing_scope_span, s.as_str());
+                        }
+
+                        self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
+                        self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
+                        self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
+                        self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
+                        self.note_version_mismatch(&mut err, &trait_ref);
+                        if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
+                            err.emit();
+                            return;
+                        }
+
+                        // Try to report a help message
+                        if !trait_ref.has_infer_types()
+                            && self.predicate_can_apply(obligation.param_env, trait_ref)
+                        {
+                            // If a where-clause may be useful, remind the
+                            // user that they can add it.
+                            //
+                            // don't display an on-unimplemented note, as
+                            // these notes will often be of the form
+                            //     "the type `T` can't be frobnicated"
+                            // which is somewhat confusing.
+                            self.suggest_restricting_param_bound(
+                                &mut err,
+                                &trait_ref,
+                                obligation.cause.body_id,
+                            );
+                        } else {
+                            if !have_alt_message {
+                                // Can't show anything else useful, try to find similar impls.
+                                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                                self.report_similar_impl_candidates(impl_candidates, &mut err);
+                            }
+                            self.suggest_change_mut(
+                                &obligation,
+                                &mut err,
+                                &trait_ref,
+                                points_at_arg,
+                            );
+                        }
+
+                        // If this error is due to `!: Trait` not implemented but `(): Trait` is
+                        // implemented, and fallback has occurred, then it could be due to a
+                        // variable that used to fallback to `()` now falling back to `!`. Issue a
+                        // note informing about the change in behaviour.
+                        if trait_predicate.skip_binder().self_ty().is_never()
+                            && fallback_has_occurred
+                        {
+                            let predicate = trait_predicate.map_bound(|mut trait_pred| {
+                                trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
+                                    self.tcx.mk_unit(),
+                                    &trait_pred.trait_ref.substs[1..],
+                                );
+                                trait_pred
+                            });
+                            let unit_obligation = Obligation {
+                                predicate: ty::Predicate::Trait(predicate),
+                                ..obligation.clone()
+                            };
+                            if self.predicate_may_hold(&unit_obligation) {
+                                err.note(
+                                    "the trait is implemented for `()`. \
+                                         Possibly this error has been caused by changes to \
+                                         Rust's type-inference algorithm \
+                                         (see: https://github.com/rust-lang/rust/issues/48950 \
+                                         for more info). Consider whether you meant to use the \
+                                         type `()` here instead.",
+                                );
+                            }
+                        }
+
+                        err
+                    }
+
+                    ty::Predicate::Subtype(ref predicate) => {
+                        // Errors for Subtype predicates show up as
+                        // `FulfillmentErrorCode::CodeSubtypeError`,
+                        // not selection error.
+                        span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
+                    }
+
+                    ty::Predicate::RegionOutlives(ref predicate) => {
+                        let predicate = self.resolve_vars_if_possible(predicate);
+                        let err = self
+                            .region_outlives_predicate(&obligation.cause, &predicate)
+                            .err()
+                            .unwrap();
+                        struct_span_err!(
+                            self.tcx.sess,
+                            span,
+                            E0279,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate,
+                            err,
+                        )
+                    }
+
+                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+                        struct_span_err!(
+                            self.tcx.sess,
+                            span,
+                            E0280,
+                            "the requirement `{}` is not satisfied",
+                            predicate
+                        )
+                    }
+
+                    ty::Predicate::ObjectSafe(trait_def_id) => {
+                        let violations = object_safety_violations(self.tcx, trait_def_id);
+                        report_object_safety_error(self.tcx, span, trait_def_id, violations)
+                    }
+
+                    ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
+                        let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
+                        let closure_span = self
+                            .tcx
+                            .sess
+                            .source_map()
+                            .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap());
+                        let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap();
+                        let mut err = struct_span_err!(
+                            self.tcx.sess,
+                            closure_span,
+                            E0525,
+                            "expected a closure that implements the `{}` trait, \
+                             but this closure only implements `{}`",
+                            kind,
+                            found_kind
+                        );
+
+                        err.span_label(
+                            closure_span,
+                            format!("this closure implements `{}`, not `{}`", found_kind, kind),
+                        );
+                        err.span_label(
+                            obligation.cause.span,
+                            format!("the requirement to implement `{}` derives from here", kind),
+                        );
+
+                        // Additional context information explaining why the closure only implements
+                        // a particular trait.
+                        if let Some(tables) = self.in_progress_tables {
+                            let tables = tables.borrow();
+                            match (found_kind, tables.closure_kind_origins().get(hir_id)) {
+                                (ty::ClosureKind::FnOnce, Some((span, name))) => {
+                                    err.span_label(
+                                        *span,
+                                        format!(
+                                            "closure is `FnOnce` because it moves the \
+                                         variable `{}` out of its environment",
+                                            name
+                                        ),
+                                    );
+                                }
+                                (ty::ClosureKind::FnMut, Some((span, name))) => {
+                                    err.span_label(
+                                        *span,
+                                        format!(
+                                            "closure is `FnMut` because it mutates the \
+                                         variable `{}` here",
+                                            name
+                                        ),
+                                    );
+                                }
+                                _ => {}
+                            }
+                        }
+
+                        err.emit();
+                        return;
+                    }
+
+                    ty::Predicate::WellFormed(ty) => {
+                        if !self.tcx.sess.opts.debugging_opts.chalk {
+                            // WF predicates cannot themselves make
+                            // errors. They can only block due to
+                            // ambiguity; otherwise, they always
+                            // degenerate into other obligations
+                            // (which may fail).
+                            span_bug!(span, "WF predicate not satisfied for {:?}", ty);
+                        } else {
+                            // FIXME: we'll need a better message which takes into account
+                            // which bounds actually failed to hold.
+                            self.tcx.sess.struct_span_err(
+                                span,
+                                &format!("the type `{}` is not well-formed (chalk)", ty),
+                            )
+                        }
+                    }
+
+                    ty::Predicate::ConstEvaluatable(..) => {
+                        // Errors for `ConstEvaluatable` predicates show up as
+                        // `SelectionError::ConstEvalFailure`,
+                        // not `Unimplemented`.
+                        span_bug!(
+                            span,
+                            "const-evaluatable requirement gave wrong error: `{:?}`",
+                            obligation
+                        )
+                    }
+                }
+            }
+
+            OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
+                let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref);
+                let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref);
+
+                if expected_trait_ref.self_ty().references_error() {
+                    return;
+                }
+
+                let found_trait_ty = found_trait_ref.self_ty();
+
+                let found_did = match found_trait_ty.kind {
+                    ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
+                    ty::Adt(def, _) => Some(def.did),
+                    _ => None,
+                };
+
+                let found_span = found_did
+                    .and_then(|did| self.tcx.hir().span_if_local(did))
+                    .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
+
+                if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+                    // We check closures twice, with obligations flowing in different directions,
+                    // but we want to complain about them only once.
+                    return;
+                }
+
+                self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+                let found = match found_trait_ref.skip_binder().substs.type_at(1).kind {
+                    ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+                    _ => vec![ArgKind::empty()],
+                };
+
+                let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+                let expected = match expected_ty.kind {
+                    ty::Tuple(ref tys) => tys
+                        .iter()
+                        .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span)))
+                        .collect(),
+                    _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
+                };
+
+                if found.len() == expected.len() {
+                    self.report_closure_arg_mismatch(
+                        span,
+                        found_span,
+                        found_trait_ref,
+                        expected_trait_ref,
+                    )
+                } else {
+                    let (closure_span, found) = found_did
+                        .and_then(|did| self.tcx.hir().get_if_local(did))
+                        .map(|node| {
+                            let (found_span, found) = self.get_fn_like_arguments(node);
+                            (Some(found_span), found)
+                        })
+                        .unwrap_or((found_span, found));
+
+                    self.report_arg_count_mismatch(
+                        span,
+                        closure_span,
+                        expected,
+                        found,
+                        found_trait_ty.is_closure(),
+                    )
+                }
+            }
+
+            TraitNotObjectSafe(did) => {
+                let violations = object_safety_violations(self.tcx, did);
+                report_object_safety_error(self.tcx, span, did, violations)
+            }
+
+            // already reported in the query
+            ConstEvalFailure(err) => {
+                if let ErrorHandled::TooGeneric = err {
+                    // Silence this error, as it can be produced during intermediate steps
+                    // when a constant is not yet able to be evaluated (but will be later).
+                    return;
+                }
+                self.tcx.sess.delay_span_bug(
+                    span,
+                    &format!("constant in type had an ignored error: {:?}", err),
+                );
+                return;
+            }
+
+            Overflow => {
+                bug!("overflow should be handled before the `report_selection_error` path");
+            }
+        };
+
+        self.note_obligation_cause(&mut err, obligation);
+        self.point_at_returns_when_relevant(&mut err, &obligation);
+
+        err.emit();
+    }
+
+    /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
+    /// with the same path as `trait_ref`, a help message about
+    /// a probable version mismatch is added to `err`
+    fn note_version_mismatch(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+    ) {
+        let get_trait_impl = |trait_def_id| {
+            let mut trait_impl = None;
+            self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| {
+                if trait_impl.is_none() {
+                    trait_impl = Some(impl_def_id);
+                }
+            });
+            trait_impl
+        };
+        let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
+        let all_traits = self.tcx.all_traits(LOCAL_CRATE);
+        let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
+            .iter()
+            .filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
+            .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
+            .collect();
+        for trait_with_same_path in traits_with_same_path {
+            if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
+                let impl_span = self.tcx.def_span(impl_def_id);
+                err.span_help(impl_span, "trait impl with same name found");
+                let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+                let crate_msg = format!(
+                    "perhaps two different versions of crate `{}` are being used?",
+                    trait_crate
+                );
+                err.note(&crate_msg);
+            }
+        }
+    }
+
+    fn mk_obligation_for_def_id(
+        &self,
+        def_id: DefId,
+        output_ty: Ty<'tcx>,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> PredicateObligation<'tcx> {
+        let new_trait_ref =
+            ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) };
+        Obligation::new(cause, param_env, new_trait_ref.to_predicate())
+    }
+}
+
+pub fn recursive_type_with_infinite_size_error(
+    tcx: TyCtxt<'tcx>,
+    type_def_id: DefId,
+) -> DiagnosticBuilder<'tcx> {
+    assert!(type_def_id.is_local());
+    let span = tcx.hir().span_if_local(type_def_id).unwrap();
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0072,
+        "recursive type `{}` has infinite size",
+        tcx.def_path_str(type_def_id)
+    );
+    err.span_label(span, "recursive type has infinite size");
+    err.help(&format!(
+        "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
+                           at some point to make `{}` representable",
+        tcx.def_path_str(type_def_id)
+    ));
+    err
+}
+
+pub fn report_object_safety_error(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    trait_def_id: DefId,
+    violations: Vec<ObjectSafetyViolation>,
+) -> DiagnosticBuilder<'tcx> {
+    let trait_str = tcx.def_path_str(trait_def_id);
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0038,
+        "the trait `{}` cannot be made into an object",
+        trait_str
+    );
+    err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
+
+    let mut reported_violations = FxHashSet::default();
+    for violation in violations {
+        if reported_violations.insert(violation.clone()) {
+            match violation.span() {
+                Some(span) => err.span_label(span, violation.error_msg()),
+                None => err.note(&violation.error_msg()),
+            };
+        }
+    }
+
+    if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
+        // Avoid emitting error caused by non-existing method (#58734)
+        err.cancel();
+    }
+
+    err
+}
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    fn maybe_report_ambiguity(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        body_id: Option<hir::BodyId>,
+    ) {
+        // Unable to successfully determine, probably means
+        // insufficient type information, but could mean
+        // ambiguous impls. The latter *ought* to be a
+        // coherence violation, so we don't report it here.
+
+        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
+        let span = obligation.cause.span;
+
+        debug!(
+            "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})",
+            predicate, obligation, body_id, obligation.cause.code,
+        );
+
+        // Ambiguity errors are often caused as fallout from earlier
+        // errors. So just ignore them if this infcx is tainted.
+        if self.is_tainted_by_errors() {
+            return;
+        }
+
+        let mut err = match predicate {
+            ty::Predicate::Trait(ref data) => {
+                let trait_ref = data.to_poly_trait_ref();
+                let self_ty = trait_ref.self_ty();
+                debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
+
+                if predicate.references_error() {
+                    return;
+                }
+                // Typically, this ambiguity should only happen if
+                // there are unresolved type inference variables
+                // (otherwise it would suggest a coherence
+                // failure). But given #21974 that is not necessarily
+                // the case -- we can have multiple where clauses that
+                // are only distinguished by a region, which results
+                // in an ambiguity even when all types are fully
+                // known, since we don't dispatch based on region
+                // relationships.
+
+                // This is kind of a hack: it frequently happens that some earlier
+                // error prevents types from being fully inferred, and then we get
+                // a bunch of uninteresting errors saying something like "<generic
+                // #0> doesn't implement Sized".  It may even be true that we
+                // could just skip over all checks where the self-ty is an
+                // inference variable, but I was afraid that there might be an
+                // inference variable created, registered as an obligation, and
+                // then never forced by writeback, and hence by skipping here we'd
+                // be ignoring the fact that we don't KNOW the type works
+                // out. Though even that would probably be harmless, given that
+                // we're only talking about builtin traits, which are known to be
+                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
+                // avoid inundating the user with unnecessary errors, but we now
+                // check upstream for type errors and dont add the obligations to
+                // begin with in those cases.
+                if self
+                    .tcx
+                    .lang_items()
+                    .sized_trait()
+                    .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+                {
+                    self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
+                    return;
+                }
+                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
+                err.note(&format!("cannot resolve `{}`", predicate));
+                if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
+                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+                } else if let (
+                    Ok(ref snippet),
+                    ObligationCauseCode::BindingObligation(ref def_id, _),
+                ) =
+                    (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
+                {
+                    let generics = self.tcx.generics_of(*def_id);
+                    if !generics.params.is_empty() && !snippet.ends_with('>') {
+                        // FIXME: To avoid spurious suggestions in functions where type arguments
+                        // where already supplied, we check the snippet to make sure it doesn't
+                        // end with a turbofish. Ideally we would have access to a `PathSegment`
+                        // instead. Otherwise we would produce the following output:
+                        //
+                        // error[E0283]: type annotations needed
+                        //   --> $DIR/issue-54954.rs:3:24
+                        //    |
+                        // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+                        //    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+                        //    |                        |
+                        //    |                        cannot infer type
+                        //    |                        help: consider specifying the type argument
+                        //    |                        in the function call:
+                        //    |                        `Tt::const_val::<[i8; 123]>::<T>`
+                        // ...
+                        // LL |     const fn const_val<T: Sized>() -> usize {
+                        //    |              --------- - required by this bound in `Tt::const_val`
+                        //    |
+                        //    = note: cannot resolve `_: Tt`
+
+                        err.span_suggestion(
+                            span,
+                            &format!(
+                                "consider specifying the type argument{} in the function call",
+                                if generics.params.len() > 1 { "s" } else { "" },
+                            ),
+                            format!(
+                                "{}::<{}>",
+                                snippet,
+                                generics
+                                    .params
+                                    .iter()
+                                    .map(|p| p.name.to_string())
+                                    .collect::<Vec<String>>()
+                                    .join(", ")
+                            ),
+                            Applicability::HasPlaceholders,
+                        );
+                    }
+                }
+                err
+            }
+
+            ty::Predicate::WellFormed(ty) => {
+                // Same hacky approach as above to avoid deluging user
+                // with error messages.
+                if ty.references_error() || self.tcx.sess.has_errors() {
+                    return;
+                }
+                self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
+            }
+
+            ty::Predicate::Subtype(ref data) => {
+                if data.references_error() || self.tcx.sess.has_errors() {
+                    // no need to overload user in such cases
+                    return;
+                }
+                let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
+                // both must be type variables, or the other would've been instantiated
+                assert!(a.is_ty_var() && b.is_ty_var());
+                self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
+            }
+            ty::Predicate::Projection(ref data) => {
+                let trait_ref = data.to_poly_trait_ref(self.tcx);
+                let self_ty = trait_ref.self_ty();
+                if predicate.references_error() {
+                    return;
+                }
+                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284);
+                err.note(&format!("cannot resolve `{}`", predicate));
+                err
+            }
+
+            _ => {
+                if self.tcx.sess.has_errors() {
+                    return;
+                }
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0284,
+                    "type annotations needed: cannot resolve `{}`",
+                    predicate,
+                );
+                err.span_label(span, &format!("cannot resolve `{}`", predicate));
+                err
+            }
+        };
+        self.note_obligation_cause(&mut err, obligation);
+        err.emit();
+    }
+
+    /// Returns `true` if the trait predicate may apply for *some* assignment
+    /// to the type parameters.
+    fn predicate_can_apply(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        pred: ty::PolyTraitRef<'tcx>,
+    ) -> bool {
+        struct ParamToVarFolder<'a, 'tcx> {
+            infcx: &'a InferCtxt<'a, 'tcx>,
+            var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+        }
+
+        impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> {
+            fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+                self.infcx.tcx
+            }
+
+            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+                if let ty::Param(ty::ParamTy { name, .. }) = ty.kind {
+                    let infcx = self.infcx;
+                    self.var_map.entry(ty).or_insert_with(|| {
+                        infcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
+                            span: DUMMY_SP,
+                        })
+                    })
+                } else {
+                    ty.super_fold_with(self)
+                }
+            }
+        }
+
+        self.probe(|_| {
+            let mut selcx = SelectionContext::new(self);
+
+            let cleaned_pred =
+                pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
+
+            let cleaned_pred = super::project::normalize(
+                &mut selcx,
+                param_env,
+                ObligationCause::dummy(),
+                &cleaned_pred,
+            )
+            .value;
+
+            let obligation =
+                Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate());
+
+            self.predicate_may_hold(&obligation)
+        })
+    }
+
+    fn note_obligation_cause(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
+        // First, attempt to add note to this error with an async-await-specific
+        // message, and fall back to regular note otherwise.
+        if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
+            self.note_obligation_cause_code(
+                err,
+                &obligation.predicate,
+                &obligation.cause.code,
+                &mut vec![],
+            );
+        }
+    }
+
+    fn is_recursive_obligation(
+        &self,
+        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+        cause_code: &ObligationCauseCode<'tcx>,
+    ) -> bool {
+        if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
+            let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
+
+            if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
+                return true;
+            }
+        }
+        false
+    }
+}
+
+/// Summarizes information
+#[derive(Clone)]
+pub enum ArgKind {
+    /// An argument of non-tuple type. Parameters are (name, ty)
+    Arg(String, String),
+
+    /// An argument of tuple type. For a "found" argument, the span is
+    /// the locationo in the source of the pattern. For a "expected"
+    /// argument, it will be None. The vector is a list of (name, ty)
+    /// strings for the components of the tuple.
+    Tuple(Option<Span>, Vec<(String, String)>),
+}
+
+impl ArgKind {
+    fn empty() -> ArgKind {
+        ArgKind::Arg("_".to_owned(), "_".to_owned())
+    }
+
+    /// Creates an `ArgKind` from the expected type of an
+    /// argument. It has no name (`_`) and an optional source span.
+    pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
+        match t.kind {
+            ty::Tuple(ref tys) => ArgKind::Tuple(
+                span,
+                tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
+            ),
+            _ => ArgKind::Arg("_".to_owned(), t.to_string()),
+        }
+    }
+}
+
+/// Suggest restricting a type param with a new bound.
+pub fn suggest_constraining_type_param(
+    generics: &hir::Generics<'_>,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    constraint: &str,
+    source_map: &SourceMap,
+    span: Span,
+) -> bool {
+    let restrict_msg = "consider further restricting this bound";
+    if let Some(param) =
+        generics.params.iter().filter(|p| p.name.ident().as_str() == param_name).next()
+    {
+        if param_name.starts_with("impl ") {
+            // `impl Trait` in argument:
+            // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
+            err.span_suggestion(
+                param.span,
+                restrict_msg,
+                // `impl CurrentTrait + MissingTrait`
+                format!("{} + {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else if generics.where_clause.predicates.is_empty() && param.bounds.is_empty() {
+            // If there are no bounds whatsoever, suggest adding a constraint
+            // to the type parameter:
+            // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
+            err.span_suggestion(
+                param.span,
+                "consider restricting this bound",
+                format!("{}: {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else if !generics.where_clause.predicates.is_empty() {
+            // There is a `where` clause, so suggest expanding it:
+            // `fn foo<T>(t: T) where T: Debug {}` →
+            // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
+            err.span_suggestion(
+                generics.where_clause.span().unwrap().shrink_to_hi(),
+                &format!("consider further restricting type parameter `{}`", param_name),
+                format!(", {}: {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            // If there is no `where` clause lean towards constraining to the
+            // type parameter:
+            // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
+            // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
+            let sp = param.span.with_hi(span.hi());
+            let span = source_map.span_through_char(sp, ':');
+            if sp != param.span && sp != span {
+                // Only suggest if we have high certainty that the span
+                // covers the colon in `foo<T: Trait>`.
+                err.span_suggestion(
+                    span,
+                    restrict_msg,
+                    format!("{}: {} + ", param_name, constraint),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    param.span,
+                    &format!("consider adding a `where {}: {}` bound", param_name, constraint),
+                );
+            }
+        }
+        return true;
+    }
+    false
+}
+
+struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
+
+impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
+    type Map = rustc::hir::map::Map<'v>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
+        hir::intravisit::NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+        match ex.kind {
+            hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
+            _ => {}
+        }
+        hir::intravisit::walk_expr(self, ex);
+    }
+
+    fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+        if body.generator_kind().is_none() {
+            if let hir::ExprKind::Block(block, None) = body.value.kind {
+                if let Some(expr) = block.expr {
+                    self.0.push(expr);
+                }
+            }
+        }
+        hir::intravisit::walk_body(self, body);
+    }
+}
diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs
new file mode 100644
index 0000000000000..9f3fc91548b21
--- /dev/null
+++ b/src/librustc/traits/error_reporting/on_unimplemented.rs
@@ -0,0 +1,199 @@
+use super::{
+    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
+};
+use crate::infer::InferCtxt;
+use crate::ty::subst::Subst;
+use crate::ty::{self, GenericParamDefKind};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::sym;
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    fn impl_similar_to(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> Option<DefId> {
+        let tcx = self.tcx;
+        let param_env = obligation.param_env;
+        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
+        let trait_self_ty = trait_ref.self_ty();
+
+        let mut self_match_impls = vec![];
+        let mut fuzzy_match_impls = vec![];
+
+        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
+            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
+            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+
+            let impl_self_ty = impl_trait_ref.self_ty();
+
+            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
+                self_match_impls.push(def_id);
+
+                if trait_ref
+                    .substs
+                    .types()
+                    .skip(1)
+                    .zip(impl_trait_ref.substs.types().skip(1))
+                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
+                {
+                    fuzzy_match_impls.push(def_id);
+                }
+            }
+        });
+
+        let impl_def_id = if self_match_impls.len() == 1 {
+            self_match_impls[0]
+        } else if fuzzy_match_impls.len() == 1 {
+            fuzzy_match_impls[0]
+        } else {
+            return None;
+        };
+
+        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
+    }
+
+    /// Used to set on_unimplemented's `ItemContext`
+    /// to be the enclosing (async) block/function/closure
+    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
+        let hir = &self.tcx.hir();
+        let node = hir.find(hir_id)?;
+        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
+            self.describe_generator(*body_id).or_else(|| {
+                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
+                    "an async function"
+                } else {
+                    "a function"
+                })
+            })
+        } else if let hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
+            ..
+        }) = &node
+        {
+            self.describe_generator(*body_id).or_else(|| {
+                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
+            })
+        } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
+            let parent_hid = hir.get_parent_node(hir_id);
+            if parent_hid != hir_id {
+                return self.describe_enclosure(parent_hid);
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+
+    crate fn on_unimplemented_note(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> OnUnimplementedNote {
+        let def_id =
+            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
+        let trait_ref = *trait_ref.skip_binder();
+
+        let mut flags = vec![];
+        flags.push((
+            sym::item_context,
+            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
+        ));
+
+        match obligation.cause.code {
+            ObligationCauseCode::BuiltinDerivedObligation(..)
+            | ObligationCauseCode::ImplDerivedObligation(..) => {}
+            _ => {
+                // this is a "direct", user-specified, rather than derived,
+                // obligation.
+                flags.push((sym::direct, None));
+            }
+        }
+
+        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
+            // FIXME: maybe also have some way of handling methods
+            // from other traits? That would require name resolution,
+            // which we might want to be some sort of hygienic.
+            //
+            // Currently I'm leaving it for what I need for `try`.
+            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
+                let method = self.tcx.item_name(item);
+                flags.push((sym::from_method, None));
+                flags.push((sym::from_method, Some(method.to_string())));
+            }
+        }
+        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
+            flags.push((sym::parent_trait, Some(t)));
+        }
+
+        if let Some(k) = obligation.cause.span.desugaring_kind() {
+            flags.push((sym::from_desugaring, None));
+            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
+        }
+        let generics = self.tcx.generics_of(def_id);
+        let self_ty = trait_ref.self_ty();
+        // This is also included through the generics list as `Self`,
+        // but the parser won't allow you to use it
+        flags.push((sym::_Self, Some(self_ty.to_string())));
+        if let Some(def) = self_ty.ty_adt_def() {
+            // We also want to be able to select self's original
+            // signature with no type arguments resolved
+            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
+        }
+
+        for param in generics.params.iter() {
+            let value = match param.kind {
+                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
+                    trait_ref.substs[param.index as usize].to_string()
+                }
+                GenericParamDefKind::Lifetime => continue,
+            };
+            let name = param.name;
+            flags.push((name, Some(value)));
+        }
+
+        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
+            flags.push((sym::crate_local, None));
+        }
+
+        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
+        if self_ty.is_integral() {
+            flags.push((sym::_Self, Some("{integral}".to_owned())));
+        }
+
+        if let ty::Array(aty, len) = self_ty.kind {
+            flags.push((sym::_Self, Some("[]".to_owned())));
+            flags.push((sym::_Self, Some(format!("[{}]", aty))));
+            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())),
+                    ));
+                }
+            }
+        }
+
+        if let Ok(Some(command)) =
+            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
+        {
+            command.evaluate(self.tcx, trait_ref, &flags[..])
+        } else {
+            OnUnimplementedNote::default()
+        }
+    }
+}
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting/suggestions.rs
similarity index 52%
rename from src/librustc/traits/error_reporting.rs
rename to src/librustc/traits/error_reporting/suggestions.rs
index 77a73aba45484..389edfa071794 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -1,1178 +1,28 @@
-// ignore-tidy-filelength
 use super::{
-    ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode,
-    MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause,
-    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote,
-    OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError,
-    TraitNotObjectSafe,
+    ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode,
+    PredicateObligation,
 };
 
-use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{self, InferCtxt};
-use crate::mir::interpret::ErrorHandled;
-use crate::session::DiagnosticMessageId;
-use crate::traits::object_safety_violations;
-use crate::ty::error::ExpectedFound;
-use crate::ty::fast_reject;
-use crate::ty::fold::TypeFolder;
-use crate::ty::subst::Subst;
-use crate::ty::GenericParamDefKind;
-use crate::ty::SubtypePredicate;
+use crate::infer::InferCtxt;
 use crate::ty::TypeckTables;
-use crate::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
     error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
 };
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
-use syntax::ast;
 
 use rustc_error_codes::*;
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn report_fulfillment_errors(
-        &self,
-        errors: &[FulfillmentError<'tcx>],
-        body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
-    ) {
-        #[derive(Debug)]
-        struct ErrorDescriptor<'tcx> {
-            predicate: ty::Predicate<'tcx>,
-            index: Option<usize>, // None if this is an old error
-        }
-
-        let mut error_map: FxHashMap<_, Vec<_>> = self
-            .reported_trait_errors
-            .borrow()
-            .iter()
-            .map(|(&span, predicates)| {
-                (
-                    span,
-                    predicates
-                        .iter()
-                        .map(|predicate| ErrorDescriptor {
-                            predicate: predicate.clone(),
-                            index: None,
-                        })
-                        .collect(),
-                )
-            })
-            .collect();
-
-        for (index, error) in errors.iter().enumerate() {
-            // We want to ignore desugarings here: spans are equivalent even
-            // if one is the result of a desugaring and the other is not.
-            let mut span = error.obligation.cause.span;
-            let expn_data = span.ctxt().outer_expn_data();
-            if let ExpnKind::Desugaring(_) = expn_data.kind {
-                span = expn_data.call_site;
-            }
-
-            error_map.entry(span).or_default().push(ErrorDescriptor {
-                predicate: error.obligation.predicate.clone(),
-                index: Some(index),
-            });
-
-            self.reported_trait_errors
-                .borrow_mut()
-                .entry(span)
-                .or_default()
-                .push(error.obligation.predicate.clone());
-        }
-
-        // We do this in 2 passes because we want to display errors in order, though
-        // maybe it *is* better to sort errors by span or something.
-        let mut is_suppressed = vec![false; errors.len()];
-        for (_, error_set) in error_map.iter() {
-            // We want to suppress "duplicate" errors with the same span.
-            for error in error_set {
-                if let Some(index) = error.index {
-                    // Suppress errors that are either:
-                    // 1) strictly implied by another error.
-                    // 2) implied by an error with a smaller index.
-                    for error2 in error_set {
-                        if error2.index.map_or(false, |index2| is_suppressed[index2]) {
-                            // Avoid errors being suppressed by already-suppressed
-                            // errors, to prevent all errors from being suppressed
-                            // at once.
-                            continue;
-                        }
-
-                        if self.error_implies(&error2.predicate, &error.predicate)
-                            && !(error2.index >= error.index
-                                && self.error_implies(&error.predicate, &error2.predicate))
-                        {
-                            info!("skipping {:?} (implied by {:?})", error, error2);
-                            is_suppressed[index] = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        for (error, suppressed) in errors.iter().zip(is_suppressed) {
-            if !suppressed {
-                self.report_fulfillment_error(error, body_id, fallback_has_occurred);
-            }
-        }
-    }
-
-    // returns if `cond` not occurring implies that `error` does not occur - i.e., that
-    // `error` occurring implies that `cond` occurs.
-    fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool {
-        if cond == error {
-            return true;
-        }
-
-        let (cond, error) = match (cond, error) {
-            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error),
-            _ => {
-                // FIXME: make this work in other cases too.
-                return false;
-            }
-        };
-
-        for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
-            if let ty::Predicate::Trait(implication) = implication {
-                let error = error.to_poly_trait_ref();
-                let implication = implication.to_poly_trait_ref();
-                // FIXME: I'm just not taking associated types at all here.
-                // Eventually I'll need to implement param-env-aware
-                // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
-                let param_env = ty::ParamEnv::empty();
-                if self.can_sub(param_env, error, implication).is_ok() {
-                    debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    fn report_fulfillment_error(
-        &self,
-        error: &FulfillmentError<'tcx>,
-        body_id: Option<hir::BodyId>,
-        fallback_has_occurred: bool,
-    ) {
-        debug!("report_fulfillment_error({:?})", error);
-        match error.code {
-            FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
-                self.report_selection_error(
-                    &error.obligation,
-                    selection_error,
-                    fallback_has_occurred,
-                    error.points_at_arg_span,
-                );
-            }
-            FulfillmentErrorCode::CodeProjectionError(ref e) => {
-                self.report_projection_error(&error.obligation, e);
-            }
-            FulfillmentErrorCode::CodeAmbiguity => {
-                self.maybe_report_ambiguity(&error.obligation, body_id);
-            }
-            FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
-                self.report_mismatched_types(
-                    &error.obligation.cause,
-                    expected_found.expected,
-                    expected_found.found,
-                    err.clone(),
-                )
-                .emit();
-            }
-        }
-    }
-
-    fn report_projection_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        error: &MismatchedProjectionTypes<'tcx>,
-    ) {
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
-
-        if predicate.references_error() {
-            return;
-        }
-
-        self.probe(|_| {
-            let err_buf;
-            let mut err = &error.err;
-            let mut values = None;
-
-            // try to find the mismatched types to report the error with.
-            //
-            // this can fail if the problem was higher-ranked, in which
-            // cause I have no idea for a good error message.
-            if let ty::Predicate::Projection(ref data) = predicate {
-                let mut selcx = SelectionContext::new(self);
-                let (data, _) = self.replace_bound_vars_with_fresh_vars(
-                    obligation.cause.span,
-                    infer::LateBoundRegionConversionTime::HigherRankedType,
-                    data,
-                );
-                let mut obligations = vec![];
-                let normalized_ty = super::normalize_projection_type(
-                    &mut selcx,
-                    obligation.param_env,
-                    data.projection_ty,
-                    obligation.cause.clone(),
-                    0,
-                    &mut obligations,
-                );
-
-                debug!(
-                    "report_projection_error obligation.cause={:?} obligation.param_env={:?}",
-                    obligation.cause, obligation.param_env
-                );
-
-                debug!(
-                    "report_projection_error normalized_ty={:?} data.ty={:?}",
-                    normalized_ty, data.ty
-                );
-
-                let is_normalized_ty_expected = match &obligation.cause.code {
-                    ObligationCauseCode::ItemObligation(_)
-                    | ObligationCauseCode::BindingObligation(_, _)
-                    | ObligationCauseCode::ObjectCastObligation(_) => false,
-                    _ => true,
-                };
-
-                if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
-                    is_normalized_ty_expected,
-                    normalized_ty,
-                    data.ty,
-                ) {
-                    values = Some(infer::ValuePairs::Types(ExpectedFound::new(
-                        is_normalized_ty_expected,
-                        normalized_ty,
-                        data.ty,
-                    )));
-
-                    err_buf = error;
-                    err = &err_buf;
-                }
-            }
-
-            let msg = format!("type mismatch resolving `{}`", predicate);
-            let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg);
-            let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
-            if fresh {
-                let mut diag = struct_span_err!(
-                    self.tcx.sess,
-                    obligation.cause.span,
-                    E0271,
-                    "type mismatch resolving `{}`",
-                    predicate
-                );
-                self.note_type_err(&mut diag, &obligation.cause, None, values, err);
-                self.note_obligation_cause(&mut diag, obligation);
-                diag.emit();
-            }
-        });
-    }
-
-    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-        /// returns the fuzzy category of a given type, or None
-        /// if the type can be equated to any type.
-        fn type_category(t: Ty<'_>) -> Option<u32> {
-            match t.kind {
-                ty::Bool => Some(0),
-                ty::Char => Some(1),
-                ty::Str => Some(2),
-                ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
-                ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
-                ty::Ref(..) | ty::RawPtr(..) => Some(5),
-                ty::Array(..) | ty::Slice(..) => Some(6),
-                ty::FnDef(..) | ty::FnPtr(..) => Some(7),
-                ty::Dynamic(..) => Some(8),
-                ty::Closure(..) => Some(9),
-                ty::Tuple(..) => Some(10),
-                ty::Projection(..) => Some(11),
-                ty::Param(..) => Some(12),
-                ty::Opaque(..) => Some(13),
-                ty::Never => Some(14),
-                ty::Adt(adt, ..) => match adt.adt_kind() {
-                    AdtKind::Struct => Some(15),
-                    AdtKind::Union => Some(16),
-                    AdtKind::Enum => Some(17),
-                },
-                ty::Generator(..) => Some(18),
-                ty::Foreign(..) => Some(19),
-                ty::GeneratorWitness(..) => Some(20),
-                ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
-                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-            }
-        }
-
-        match (type_category(a), type_category(b)) {
-            (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) {
-                (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
-                _ => cat_a == cat_b,
-            },
-            // infer and error can be equated to all types
-            _ => true,
-        }
-    }
-
-    fn impl_similar_to(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> Option<DefId> {
-        let tcx = self.tcx;
-        let param_env = obligation.param_env;
-        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
-        let trait_self_ty = trait_ref.self_ty();
-
-        let mut self_match_impls = vec![];
-        let mut fuzzy_match_impls = vec![];
-
-        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
-            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
-            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
-
-            let impl_self_ty = impl_trait_ref.self_ty();
-
-            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
-                self_match_impls.push(def_id);
-
-                if trait_ref
-                    .substs
-                    .types()
-                    .skip(1)
-                    .zip(impl_trait_ref.substs.types().skip(1))
-                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
-                {
-                    fuzzy_match_impls.push(def_id);
-                }
-            }
-        });
-
-        let impl_def_id = if self_match_impls.len() == 1 {
-            self_match_impls[0]
-        } else if fuzzy_match_impls.len() == 1 {
-            fuzzy_match_impls[0]
-        } else {
-            return None;
-        };
-
-        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
-    }
-
-    fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
-        self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind {
-            hir::GeneratorKind::Gen => "a generator",
-            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
-            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
-            hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
-        })
-    }
-
-    /// Used to set on_unimplemented's `ItemContext`
-    /// to be the enclosing (async) block/function/closure
-    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
-        let hir = &self.tcx.hir();
-        let node = hir.find(hir_id)?;
-        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
-            self.describe_generator(*body_id).or_else(|| {
-                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
-                    "an async function"
-                } else {
-                    "a function"
-                })
-            })
-        } else if let hir::Node::Expr(hir::Expr {
-            kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
-            ..
-        }) = &node
-        {
-            self.describe_generator(*body_id).or_else(|| {
-                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
-            })
-        } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
-            let parent_hid = hir.get_parent_node(hir_id);
-            if parent_hid != hir_id {
-                return self.describe_enclosure(parent_hid);
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-
-    fn on_unimplemented_note(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> OnUnimplementedNote {
-        let def_id =
-            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
-        let trait_ref = *trait_ref.skip_binder();
-
-        let mut flags = vec![];
-        flags.push((
-            sym::item_context,
-            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
-        ));
-
-        match obligation.cause.code {
-            ObligationCauseCode::BuiltinDerivedObligation(..)
-            | ObligationCauseCode::ImplDerivedObligation(..) => {}
-            _ => {
-                // this is a "direct", user-specified, rather than derived,
-                // obligation.
-                flags.push((sym::direct, None));
-            }
-        }
-
-        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
-            // FIXME: maybe also have some way of handling methods
-            // from other traits? That would require name resolution,
-            // which we might want to be some sort of hygienic.
-            //
-            // Currently I'm leaving it for what I need for `try`.
-            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
-                let method = self.tcx.item_name(item);
-                flags.push((sym::from_method, None));
-                flags.push((sym::from_method, Some(method.to_string())));
-            }
-        }
-        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
-            flags.push((sym::parent_trait, Some(t)));
-        }
-
-        if let Some(k) = obligation.cause.span.desugaring_kind() {
-            flags.push((sym::from_desugaring, None));
-            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
-        }
-        let generics = self.tcx.generics_of(def_id);
-        let self_ty = trait_ref.self_ty();
-        // This is also included through the generics list as `Self`,
-        // but the parser won't allow you to use it
-        flags.push((sym::_Self, Some(self_ty.to_string())));
-        if let Some(def) = self_ty.ty_adt_def() {
-            // We also want to be able to select self's original
-            // signature with no type arguments resolved
-            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
-        }
-
-        for param in generics.params.iter() {
-            let value = match param.kind {
-                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
-                    trait_ref.substs[param.index as usize].to_string()
-                }
-                GenericParamDefKind::Lifetime => continue,
-            };
-            let name = param.name;
-            flags.push((name, Some(value)));
-        }
-
-        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
-            flags.push((sym::crate_local, None));
-        }
-
-        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
-        if self_ty.is_integral() {
-            flags.push((sym::_Self, Some("{integral}".to_owned())));
-        }
-
-        if let ty::Array(aty, len) = self_ty.kind {
-            flags.push((sym::_Self, Some("[]".to_owned())));
-            flags.push((sym::_Self, Some(format!("[{}]", aty))));
-            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())),
-                    ));
-                }
-            }
-        }
-
-        if let Ok(Some(command)) =
-            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
-        {
-            command.evaluate(self.tcx, trait_ref, &flags[..])
-        } else {
-            OnUnimplementedNote::default()
-        }
-    }
-
-    fn find_similar_impl_candidates(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<ty::TraitRef<'tcx>> {
-        let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true);
-        let all_impls = self.tcx.all_impls(trait_ref.def_id());
-
-        match simp {
-            Some(simp) => all_impls
-                .iter()
-                .filter_map(|&def_id| {
-                    let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                    let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
-                    if let Some(imp_simp) = imp_simp {
-                        if simp != imp_simp {
-                            return None;
-                        }
-                    }
-
-                    Some(imp)
-                })
-                .collect(),
-            None => {
-                all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect()
-            }
-        }
-    }
-
-    fn report_similar_impl_candidates(
-        &self,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if impl_candidates.is_empty() {
-            return;
-        }
-
-        let len = impl_candidates.len();
-        let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 };
-
-        let normalize = |candidate| {
-            self.tcx.infer_ctxt().enter(|ref infcx| {
-                let normalized = infcx
-                    .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-                    .normalize(candidate)
-                    .ok();
-                match normalized {
-                    Some(normalized) => format!("\n  {:?}", normalized.value),
-                    None => format!("\n  {:?}", candidate),
-                }
-            })
-        };
-
-        // Sort impl candidates so that ordering is consistent for UI tests.
-        let mut normalized_impl_candidates =
-            impl_candidates.iter().map(normalize).collect::<Vec<String>>();
-
-        // Sort before taking the `..end` range,
-        // because the ordering of `impl_candidates` may not be deterministic:
-        // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
-        normalized_impl_candidates.sort();
-
-        err.help(&format!(
-            "the following implementations were found:{}{}",
-            normalized_impl_candidates[..end].join(""),
-            if len > 5 { format!("\nand {} others", len - 4) } else { String::new() }
-        ));
-    }
-
-    /// Reports that an overflow has occurred and halts compilation. We
-    /// halt compilation unconditionally because it is important that
-    /// overflows never be masked -- they basically represent computations
-    /// whose result could not be truly determined and thus we can't say
-    /// if the program type checks or not -- and they are unusual
-    /// occurrences in any case.
-    pub fn report_overflow_error<T>(
-        &self,
-        obligation: &Obligation<'tcx, T>,
-        suggest_increasing_limit: bool,
-    ) -> !
-    where
-        T: fmt::Display + TypeFoldable<'tcx>,
-    {
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            obligation.cause.span,
-            E0275,
-            "overflow evaluating the requirement `{}`",
-            predicate
-        );
-
-        if suggest_increasing_limit {
-            self.suggest_new_overflow_limit(&mut err);
-        }
-
-        self.note_obligation_cause_code(
-            &mut err,
-            &obligation.predicate,
-            &obligation.cause.code,
-            &mut vec![],
-        );
-
-        err.emit();
-        self.tcx.sess.abort_if_errors();
-        bug!();
-    }
-
-    /// Reports that a cycle was detected which led to overflow and halts
-    /// compilation. This is equivalent to `report_overflow_error` except
-    /// that we can give a more helpful error message (and, in particular,
-    /// we do not suggest increasing the overflow limit, which is not
-    /// going to help).
-    pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
-        let cycle = self.resolve_vars_if_possible(&cycle.to_owned());
-        assert!(cycle.len() > 0);
-
-        debug!("report_overflow_error_cycle: cycle={:?}", cycle);
-
-        self.report_overflow_error(&cycle[0], false);
-    }
-
-    pub fn report_extra_impl_obligation(
-        &self,
-        error_span: Span,
-        item_name: ast::Name,
-        _impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-        requirement: &dyn fmt::Display,
-    ) -> DiagnosticBuilder<'tcx> {
-        let msg = "impl has stricter requirements than trait";
-        let sp = self.tcx.sess.source_map().def_span(error_span);
-
-        let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
-
-        if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
-            let span = self.tcx.sess.source_map().def_span(trait_item_span);
-            err.span_label(span, format!("definition of `{}` from trait", item_name));
-        }
-
-        err.span_label(sp, format!("impl has extra requirement {}", requirement));
-
-        err
-    }
-
-    /// Gets the parent trait chain start
-    fn get_parent_trait_ref(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-    ) -> Option<(String, Option<Span>)> {
-        match code {
-            &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
-                match self.get_parent_trait_ref(&data.parent_code) {
-                    Some(t) => Some(t),
-                    None => {
-                        let ty = parent_trait_ref.skip_binder().self_ty();
-                        let span =
-                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
-                        Some((ty.to_string(), span))
-                    }
-                }
-            }
-            _ => None,
-        }
-    }
-
-    pub fn report_selection_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        error: &SelectionError<'tcx>,
-        fallback_has_occurred: bool,
-        points_at_arg: bool,
-    ) {
-        let tcx = self.tcx;
-        let span = obligation.cause.span;
-
-        let mut err = match *error {
-            SelectionError::Unimplemented => {
-                if let ObligationCauseCode::CompareImplMethodObligation {
-                    item_name,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                }
-                | ObligationCauseCode::CompareImplTypeObligation {
-                    item_name,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                } = obligation.cause.code
-                {
-                    self.report_extra_impl_obligation(
-                        span,
-                        item_name,
-                        impl_item_def_id,
-                        trait_item_def_id,
-                        &format!("`{}`", obligation.predicate),
-                    )
-                    .emit();
-                    return;
-                }
-                match obligation.predicate {
-                    ty::Predicate::Trait(ref trait_predicate) => {
-                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
-
-                        if self.tcx.sess.has_errors() && trait_predicate.references_error() {
-                            return;
-                        }
-                        let trait_ref = trait_predicate.to_poly_trait_ref();
-                        let (post_message, pre_message, type_def) = self
-                            .get_parent_trait_ref(&obligation.cause.code)
-                            .map(|(t, s)| {
-                                (
-                                    format!(" in `{}`", t),
-                                    format!("within `{}`, ", t),
-                                    s.map(|s| (format!("within this `{}`", t), s)),
-                                )
-                            })
-                            .unwrap_or_default();
-
-                        let OnUnimplementedNote { message, label, note, enclosing_scope } =
-                            self.on_unimplemented_note(trait_ref, obligation);
-                        let have_alt_message = message.is_some() || label.is_some();
-                        let is_try = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(span)
-                            .map(|s| &s == "?")
-                            .unwrap_or(false);
-                        let is_from = format!("{}", trait_ref.print_only_trait_path())
-                            .starts_with("std::convert::From<");
-                        let (message, note) = if is_try && is_from {
-                            (
-                                Some(format!(
-                                    "`?` couldn't convert the error to `{}`",
-                                    trait_ref.self_ty(),
-                                )),
-                                Some(
-                                    "the question mark operation (`?`) implicitly performs a \
-                                     conversion on the error value using the `From` trait"
-                                        .to_owned(),
-                                ),
-                            )
-                        } else {
-                            (message, note)
-                        };
-
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            span,
-                            E0277,
-                            "{}",
-                            message.unwrap_or_else(|| format!(
-                                "the trait bound `{}` is not satisfied{}",
-                                trait_ref.to_predicate(),
-                                post_message,
-                            ))
-                        );
-
-                        let explanation =
-                            if obligation.cause.code == ObligationCauseCode::MainFunctionType {
-                                "consider using `()`, or a `Result`".to_owned()
-                            } else {
-                                format!(
-                                    "{}the trait `{}` is not implemented for `{}`",
-                                    pre_message,
-                                    trait_ref.print_only_trait_path(),
-                                    trait_ref.self_ty(),
-                                )
-                            };
-
-                        if self.suggest_add_reference_to_arg(
-                            &obligation,
-                            &mut err,
-                            &trait_ref,
-                            points_at_arg,
-                            have_alt_message,
-                        ) {
-                            self.note_obligation_cause(&mut err, obligation);
-                            err.emit();
-                            return;
-                        }
-                        if let Some(ref s) = label {
-                            // If it has a custom `#[rustc_on_unimplemented]`
-                            // error message, let's display it as the label!
-                            err.span_label(span, s.as_str());
-                            err.help(&explanation);
-                        } else {
-                            err.span_label(span, explanation);
-                        }
-                        if let Some((msg, span)) = type_def {
-                            err.span_label(span, &msg);
-                        }
-                        if let Some(ref s) = note {
-                            // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
-                            err.note(s.as_str());
-                        }
-                        if let Some(ref s) = enclosing_scope {
-                            let enclosing_scope_span = tcx.def_span(
-                                tcx.hir()
-                                    .opt_local_def_id(obligation.cause.body_id)
-                                    .unwrap_or_else(|| {
-                                        tcx.hir().body_owner_def_id(hir::BodyId {
-                                            hir_id: obligation.cause.body_id,
-                                        })
-                                    }),
-                            );
-
-                            err.span_label(enclosing_scope_span, s.as_str());
-                        }
-
-                        self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
-                        self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
-                        self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
-                        self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
-                        self.note_version_mismatch(&mut err, &trait_ref);
-                        if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
-                            err.emit();
-                            return;
-                        }
-
-                        // Try to report a help message
-                        if !trait_ref.has_infer_types()
-                            && self.predicate_can_apply(obligation.param_env, trait_ref)
-                        {
-                            // If a where-clause may be useful, remind the
-                            // user that they can add it.
-                            //
-                            // don't display an on-unimplemented note, as
-                            // these notes will often be of the form
-                            //     "the type `T` can't be frobnicated"
-                            // which is somewhat confusing.
-                            self.suggest_restricting_param_bound(
-                                &mut err,
-                                &trait_ref,
-                                obligation.cause.body_id,
-                            );
-                        } else {
-                            if !have_alt_message {
-                                // Can't show anything else useful, try to find similar impls.
-                                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
-                                self.report_similar_impl_candidates(impl_candidates, &mut err);
-                            }
-                            self.suggest_change_mut(
-                                &obligation,
-                                &mut err,
-                                &trait_ref,
-                                points_at_arg,
-                            );
-                        }
-
-                        // If this error is due to `!: Trait` not implemented but `(): Trait` is
-                        // implemented, and fallback has occurred, then it could be due to a
-                        // variable that used to fallback to `()` now falling back to `!`. Issue a
-                        // note informing about the change in behaviour.
-                        if trait_predicate.skip_binder().self_ty().is_never()
-                            && fallback_has_occurred
-                        {
-                            let predicate = trait_predicate.map_bound(|mut trait_pred| {
-                                trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
-                                    self.tcx.mk_unit(),
-                                    &trait_pred.trait_ref.substs[1..],
-                                );
-                                trait_pred
-                            });
-                            let unit_obligation = Obligation {
-                                predicate: ty::Predicate::Trait(predicate),
-                                ..obligation.clone()
-                            };
-                            if self.predicate_may_hold(&unit_obligation) {
-                                err.note(
-                                    "the trait is implemented for `()`. \
-                                         Possibly this error has been caused by changes to \
-                                         Rust's type-inference algorithm \
-                                         (see: https://github.com/rust-lang/rust/issues/48950 \
-                                         for more info). Consider whether you meant to use the \
-                                         type `()` here instead.",
-                                );
-                            }
-                        }
-
-                        err
-                    }
-
-                    ty::Predicate::Subtype(ref predicate) => {
-                        // Errors for Subtype predicates show up as
-                        // `FulfillmentErrorCode::CodeSubtypeError`,
-                        // not selection error.
-                        span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
-                    }
-
-                    ty::Predicate::RegionOutlives(ref predicate) => {
-                        let predicate = self.resolve_vars_if_possible(predicate);
-                        let err = self
-                            .region_outlives_predicate(&obligation.cause, &predicate)
-                            .err()
-                            .unwrap();
-                        struct_span_err!(
-                            self.tcx.sess,
-                            span,
-                            E0279,
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate,
-                            err,
-                        )
-                    }
-
-                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
-                        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
-                        struct_span_err!(
-                            self.tcx.sess,
-                            span,
-                            E0280,
-                            "the requirement `{}` is not satisfied",
-                            predicate
-                        )
-                    }
-
-                    ty::Predicate::ObjectSafe(trait_def_id) => {
-                        let violations = object_safety_violations(self.tcx, trait_def_id);
-                        report_object_safety_error(self.tcx, span, trait_def_id, violations)
-                    }
-
-                    ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
-                        let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
-                        let closure_span = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap());
-                        let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap();
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            closure_span,
-                            E0525,
-                            "expected a closure that implements the `{}` trait, \
-                             but this closure only implements `{}`",
-                            kind,
-                            found_kind
-                        );
-
-                        err.span_label(
-                            closure_span,
-                            format!("this closure implements `{}`, not `{}`", found_kind, kind),
-                        );
-                        err.span_label(
-                            obligation.cause.span,
-                            format!("the requirement to implement `{}` derives from here", kind),
-                        );
-
-                        // Additional context information explaining why the closure only implements
-                        // a particular trait.
-                        if let Some(tables) = self.in_progress_tables {
-                            let tables = tables.borrow();
-                            match (found_kind, tables.closure_kind_origins().get(hir_id)) {
-                                (ty::ClosureKind::FnOnce, Some((span, name))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnOnce` because it moves the \
-                                         variable `{}` out of its environment",
-                                            name
-                                        ),
-                                    );
-                                }
-                                (ty::ClosureKind::FnMut, Some((span, name))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnMut` because it mutates the \
-                                         variable `{}` here",
-                                            name
-                                        ),
-                                    );
-                                }
-                                _ => {}
-                            }
-                        }
-
-                        err.emit();
-                        return;
-                    }
-
-                    ty::Predicate::WellFormed(ty) => {
-                        if !self.tcx.sess.opts.debugging_opts.chalk {
-                            // WF predicates cannot themselves make
-                            // errors. They can only block due to
-                            // ambiguity; otherwise, they always
-                            // degenerate into other obligations
-                            // (which may fail).
-                            span_bug!(span, "WF predicate not satisfied for {:?}", ty);
-                        } else {
-                            // FIXME: we'll need a better message which takes into account
-                            // which bounds actually failed to hold.
-                            self.tcx.sess.struct_span_err(
-                                span,
-                                &format!("the type `{}` is not well-formed (chalk)", ty),
-                            )
-                        }
-                    }
-
-                    ty::Predicate::ConstEvaluatable(..) => {
-                        // Errors for `ConstEvaluatable` predicates show up as
-                        // `SelectionError::ConstEvalFailure`,
-                        // not `Unimplemented`.
-                        span_bug!(
-                            span,
-                            "const-evaluatable requirement gave wrong error: `{:?}`",
-                            obligation
-                        )
-                    }
-                }
-            }
-
-            OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
-                let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref);
-                let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref);
-
-                if expected_trait_ref.self_ty().references_error() {
-                    return;
-                }
-
-                let found_trait_ty = found_trait_ref.self_ty();
-
-                let found_did = match found_trait_ty.kind {
-                    ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
-                    ty::Adt(def, _) => Some(def.did),
-                    _ => None,
-                };
-
-                let found_span = found_did
-                    .and_then(|did| self.tcx.hir().span_if_local(did))
-                    .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
-
-                if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
-                    // We check closures twice, with obligations flowing in different directions,
-                    // but we want to complain about them only once.
-                    return;
-                }
-
-                self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
-
-                let found = match found_trait_ref.skip_binder().substs.type_at(1).kind {
-                    ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
-                    _ => vec![ArgKind::empty()],
-                };
-
-                let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
-                let expected = match expected_ty.kind {
-                    ty::Tuple(ref tys) => tys
-                        .iter()
-                        .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span)))
-                        .collect(),
-                    _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
-                };
-
-                if found.len() == expected.len() {
-                    self.report_closure_arg_mismatch(
-                        span,
-                        found_span,
-                        found_trait_ref,
-                        expected_trait_ref,
-                    )
-                } else {
-                    let (closure_span, found) = found_did
-                        .and_then(|did| self.tcx.hir().get_if_local(did))
-                        .map(|node| {
-                            let (found_span, found) = self.get_fn_like_arguments(node);
-                            (Some(found_span), found)
-                        })
-                        .unwrap_or((found_span, found));
-
-                    self.report_arg_count_mismatch(
-                        span,
-                        closure_span,
-                        expected,
-                        found,
-                        found_trait_ty.is_closure(),
-                    )
-                }
-            }
-
-            TraitNotObjectSafe(did) => {
-                let violations = object_safety_violations(self.tcx, did);
-                report_object_safety_error(self.tcx, span, did, violations)
-            }
-
-            // already reported in the query
-            ConstEvalFailure(err) => {
-                if let ErrorHandled::TooGeneric = err {
-                    // Silence this error, as it can be produced during intermediate steps
-                    // when a constant is not yet able to be evaluated (but will be later).
-                    return;
-                }
-                self.tcx.sess.delay_span_bug(
-                    span,
-                    &format!("constant in type had an ignored error: {:?}", err),
-                );
-                return;
-            }
-
-            Overflow => {
-                bug!("overflow should be handled before the `report_selection_error` path");
-            }
-        };
-
-        self.note_obligation_cause(&mut err, obligation);
-        self.point_at_returns_when_relevant(&mut err, &obligation);
-
-        err.emit();
-    }
-
-    /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
-    /// with the same path as `trait_ref`, a help message about
-    /// a probable version mismatch is added to `err`
-    fn note_version_mismatch(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) {
-        let get_trait_impl = |trait_def_id| {
-            let mut trait_impl = None;
-            self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| {
-                if trait_impl.is_none() {
-                    trait_impl = Some(impl_def_id);
-                }
-            });
-            trait_impl
-        };
-        let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
-        let all_traits = self.tcx.all_traits(LOCAL_CRATE);
-        let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
-            .iter()
-            .filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
-            .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
-            .collect();
-        for trait_with_same_path in traits_with_same_path {
-            if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
-                let impl_span = self.tcx.def_span(impl_def_id);
-                err.span_help(impl_span, "trait impl with same name found");
-                let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
-                let crate_msg = format!(
-                    "perhaps two different versions of crate `{}` are being used?",
-                    trait_crate
-                );
-                err.note(&crate_msg);
-            }
-        }
-    }
-    fn suggest_restricting_param_bound(
+    crate fn suggest_restricting_param_bound(
         &self,
         mut err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::PolyTraitRef<'_>,
@@ -1318,7 +168,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
     /// suggestion to borrow the initializer in order to use have a slice instead.
-    fn suggest_borrow_on_unsized_slice(
+    crate fn suggest_borrow_on_unsized_slice(
         &self,
         code: &ObligationCauseCode<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1342,22 +192,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn mk_obligation_for_def_id(
-        &self,
-        def_id: DefId,
-        output_ty: Ty<'tcx>,
-        cause: ObligationCause<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> PredicateObligation<'tcx> {
-        let new_trait_ref =
-            ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) };
-        Obligation::new(cause, param_env, new_trait_ref.to_predicate())
-    }
-
     /// Given a closure's `DefId`, return the given name of the closure.
     ///
     /// This doesn't account for reassignments, but it's only used for suggestions.
-    fn get_closure_name(
+    crate fn get_closure_name(
         &self,
         def_id: DefId,
         err: &mut DiagnosticBuilder<'_>,
@@ -1395,7 +233,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
     /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
     /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
-    fn suggest_fn_call(
+    crate fn suggest_fn_call(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
@@ -1479,7 +317,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_add_reference_to_arg(
+    crate fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1548,7 +386,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
     /// suggest removing these references until we reach a type that implements the trait.
-    fn suggest_remove_reference(
+    crate fn suggest_remove_reference(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1608,7 +446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     /// Check if the trait bound is implemented for a different mutability and note it in the
     /// final error.
-    fn suggest_change_mut(
+    crate fn suggest_change_mut(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1672,7 +510,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_semicolon_removal(
+    crate fn suggest_semicolon_removal(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1705,7 +543,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_impl_trait(
+    crate fn suggest_impl_trait(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
         span: Span,
@@ -1865,7 +703,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         false
     }
 
-    fn point_at_returns_when_relevant(
+    crate fn point_at_returns_when_relevant(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
@@ -2110,14 +948,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         err
     }
 
-    fn report_closure_arg_mismatch(
+    crate fn report_closure_arg_mismatch(
         &self,
         span: Span,
         found_span: Option<Span>,
         expected_ref: ty::PolyTraitRef<'tcx>,
         found: ty::PolyTraitRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
-        fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> String {
+        crate fn build_fn_sig_string<'tcx>(
+            tcx: TyCtxt<'tcx>,
+            trait_ref: &ty::TraitRef<'tcx>,
+        ) -> String {
             let inputs = trait_ref.substs.type_at(1);
             let sig = if let ty::Tuple(inputs) = inputs.kind {
                 tcx.mk_fn_sig(
@@ -2165,238 +1006,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 }
 
-pub fn recursive_type_with_infinite_size_error(
-    tcx: TyCtxt<'tcx>,
-    type_def_id: DefId,
-) -> DiagnosticBuilder<'tcx> {
-    assert!(type_def_id.is_local());
-    let span = tcx.hir().span_if_local(type_def_id).unwrap();
-    let span = tcx.sess.source_map().def_span(span);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        span,
-        E0072,
-        "recursive type `{}` has infinite size",
-        tcx.def_path_str(type_def_id)
-    );
-    err.span_label(span, "recursive type has infinite size");
-    err.help(&format!(
-        "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
-                           at some point to make `{}` representable",
-        tcx.def_path_str(type_def_id)
-    ));
-    err
-}
-
-pub fn report_object_safety_error(
-    tcx: TyCtxt<'tcx>,
-    span: Span,
-    trait_def_id: DefId,
-    violations: Vec<ObjectSafetyViolation>,
-) -> DiagnosticBuilder<'tcx> {
-    let trait_str = tcx.def_path_str(trait_def_id);
-    let span = tcx.sess.source_map().def_span(span);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        span,
-        E0038,
-        "the trait `{}` cannot be made into an object",
-        trait_str
-    );
-    err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
-
-    let mut reported_violations = FxHashSet::default();
-    for violation in violations {
-        if reported_violations.insert(violation.clone()) {
-            match violation.span() {
-                Some(span) => err.span_label(span, violation.error_msg()),
-                None => err.note(&violation.error_msg()),
-            };
-        }
-    }
-
-    if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
-        // Avoid emitting error caused by non-existing method (#58734)
-        err.cancel();
-    }
-
-    err
-}
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    fn maybe_report_ambiguity(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        body_id: Option<hir::BodyId>,
-    ) {
-        // Unable to successfully determine, probably means
-        // insufficient type information, but could mean
-        // ambiguous impls. The latter *ought* to be a
-        // coherence violation, so we don't report it here.
-
-        let predicate = self.resolve_vars_if_possible(&obligation.predicate);
-        let span = obligation.cause.span;
-
-        debug!(
-            "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})",
-            predicate, obligation, body_id, obligation.cause.code,
-        );
-
-        // Ambiguity errors are often caused as fallout from earlier
-        // errors. So just ignore them if this infcx is tainted.
-        if self.is_tainted_by_errors() {
-            return;
-        }
-
-        let mut err = match predicate {
-            ty::Predicate::Trait(ref data) => {
-                let trait_ref = data.to_poly_trait_ref();
-                let self_ty = trait_ref.self_ty();
-                debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
-
-                if predicate.references_error() {
-                    return;
-                }
-                // Typically, this ambiguity should only happen if
-                // there are unresolved type inference variables
-                // (otherwise it would suggest a coherence
-                // failure). But given #21974 that is not necessarily
-                // the case -- we can have multiple where clauses that
-                // are only distinguished by a region, which results
-                // in an ambiguity even when all types are fully
-                // known, since we don't dispatch based on region
-                // relationships.
-
-                // This is kind of a hack: it frequently happens that some earlier
-                // error prevents types from being fully inferred, and then we get
-                // a bunch of uninteresting errors saying something like "<generic
-                // #0> doesn't implement Sized".  It may even be true that we
-                // could just skip over all checks where the self-ty is an
-                // inference variable, but I was afraid that there might be an
-                // inference variable created, registered as an obligation, and
-                // then never forced by writeback, and hence by skipping here we'd
-                // be ignoring the fact that we don't KNOW the type works
-                // out. Though even that would probably be harmless, given that
-                // we're only talking about builtin traits, which are known to be
-                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
-                // avoid inundating the user with unnecessary errors, but we now
-                // check upstream for type errors and dont add the obligations to
-                // begin with in those cases.
-                if self
-                    .tcx
-                    .lang_items()
-                    .sized_trait()
-                    .map_or(false, |sized_id| sized_id == trait_ref.def_id())
-                {
-                    self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
-                    return;
-                }
-                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
-                err.note(&format!("cannot resolve `{}`", predicate));
-                if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
-                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
-                } else if let (
-                    Ok(ref snippet),
-                    ObligationCauseCode::BindingObligation(ref def_id, _),
-                ) =
-                    (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
-                {
-                    let generics = self.tcx.generics_of(*def_id);
-                    if !generics.params.is_empty() && !snippet.ends_with('>') {
-                        // FIXME: To avoid spurious suggestions in functions where type arguments
-                        // where already supplied, we check the snippet to make sure it doesn't
-                        // end with a turbofish. Ideally we would have access to a `PathSegment`
-                        // instead. Otherwise we would produce the following output:
-                        //
-                        // error[E0283]: type annotations needed
-                        //   --> $DIR/issue-54954.rs:3:24
-                        //    |
-                        // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
-                        //    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
-                        //    |                        |
-                        //    |                        cannot infer type
-                        //    |                        help: consider specifying the type argument
-                        //    |                        in the function call:
-                        //    |                        `Tt::const_val::<[i8; 123]>::<T>`
-                        // ...
-                        // LL |     const fn const_val<T: Sized>() -> usize {
-                        //    |              --------- - required by this bound in `Tt::const_val`
-                        //    |
-                        //    = note: cannot resolve `_: Tt`
-
-                        err.span_suggestion(
-                            span,
-                            &format!(
-                                "consider specifying the type argument{} in the function call",
-                                if generics.params.len() > 1 { "s" } else { "" },
-                            ),
-                            format!(
-                                "{}::<{}>",
-                                snippet,
-                                generics
-                                    .params
-                                    .iter()
-                                    .map(|p| p.name.to_string())
-                                    .collect::<Vec<String>>()
-                                    .join(", ")
-                            ),
-                            Applicability::HasPlaceholders,
-                        );
-                    }
-                }
-                err
-            }
-
-            ty::Predicate::WellFormed(ty) => {
-                // Same hacky approach as above to avoid deluging user
-                // with error messages.
-                if ty.references_error() || self.tcx.sess.has_errors() {
-                    return;
-                }
-                self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
-            }
-
-            ty::Predicate::Subtype(ref data) => {
-                if data.references_error() || self.tcx.sess.has_errors() {
-                    // no need to overload user in such cases
-                    return;
-                }
-                let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
-                // both must be type variables, or the other would've been instantiated
-                assert!(a.is_ty_var() && b.is_ty_var());
-                self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
-            }
-            ty::Predicate::Projection(ref data) => {
-                let trait_ref = data.to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.self_ty();
-                if predicate.references_error() {
-                    return;
-                }
-                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284);
-                err.note(&format!("cannot resolve `{}`", predicate));
-                err
-            }
-
-            _ => {
-                if self.tcx.sess.has_errors() {
-                    return;
-                }
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0284,
-                    "type annotations needed: cannot resolve `{}`",
-                    predicate,
-                );
-                err.span_label(span, &format!("cannot resolve `{}`", predicate));
-                err
-            }
-        };
-        self.note_obligation_cause(&mut err, obligation);
-        err.emit();
-    }
-
-    fn suggest_fully_qualified_path(
+    crate fn suggest_fully_qualified_path(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         def_id: DefId,
@@ -2420,76 +1031,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    /// Returns `true` if the trait predicate may apply for *some* assignment
-    /// to the type parameters.
-    fn predicate_can_apply(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitRef<'tcx>,
-    ) -> bool {
-        struct ParamToVarFolder<'a, 'tcx> {
-            infcx: &'a InferCtxt<'a, 'tcx>,
-            var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
-        }
-
-        impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> {
-            fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-                self.infcx.tcx
-            }
-
-            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-                if let ty::Param(ty::ParamTy { name, .. }) = ty.kind {
-                    let infcx = self.infcx;
-                    self.var_map.entry(ty).or_insert_with(|| {
-                        infcx.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
-                            span: DUMMY_SP,
-                        })
-                    })
-                } else {
-                    ty.super_fold_with(self)
-                }
-            }
-        }
-
-        self.probe(|_| {
-            let mut selcx = SelectionContext::new(self);
-
-            let cleaned_pred =
-                pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
-
-            let cleaned_pred = super::project::normalize(
-                &mut selcx,
-                param_env,
-                ObligationCause::dummy(),
-                &cleaned_pred,
-            )
-            .value;
-
-            let obligation =
-                Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate());
-
-            self.predicate_may_hold(&obligation)
-        })
-    }
-
-    fn note_obligation_cause(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        obligation: &PredicateObligation<'tcx>,
-    ) {
-        // First, attempt to add note to this error with an async-await-specific
-        // message, and fall back to regular note otherwise.
-        if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
-            self.note_obligation_cause_code(
-                err,
-                &obligation.predicate,
-                &obligation.cause.code,
-                &mut vec![],
-            );
-        }
-    }
-
     /// Adds an async-await specific note to the diagnostic when the future does not implement
     /// an auto trait because of a captured type.
     ///
@@ -2532,7 +1073,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// ```
     ///
     /// Returns `true` if an async-await specific note was added to the diagnostic.
-    fn maybe_note_obligation_cause_for_async_await(
+    crate fn maybe_note_obligation_cause_for_async_await(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
@@ -2712,7 +1253,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     /// Unconditionally adds the diagnostic note described in
     /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
-    fn note_obligation_cause_for_async_await(
+    crate fn note_obligation_cause_for_async_await(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         target_span: Span,
@@ -2838,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         );
     }
 
-    fn note_obligation_cause_code<T>(
+    crate fn note_obligation_cause_code<T>(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         predicate: &T,
@@ -3053,7 +1594,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
+    crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
         let current_limit = self.tcx.sess.recursion_limit.get();
         let suggested_limit = current_limit * 2;
         err.help(&format!(
@@ -3061,52 +1602,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             suggested_limit
         ));
     }
-
-    fn is_recursive_obligation(
-        &self,
-        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
-        cause_code: &ObligationCauseCode<'tcx>,
-    ) -> bool {
-        if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
-            let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
-
-            if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
-                return true;
-            }
-        }
-        false
-    }
-}
-
-/// Summarizes information
-#[derive(Clone)]
-pub enum ArgKind {
-    /// An argument of non-tuple type. Parameters are (name, ty)
-    Arg(String, String),
-
-    /// An argument of tuple type. For a "found" argument, the span is
-    /// the locationo in the source of the pattern. For a "expected"
-    /// argument, it will be None. The vector is a list of (name, ty)
-    /// strings for the components of the tuple.
-    Tuple(Option<Span>, Vec<(String, String)>),
-}
-
-impl ArgKind {
-    fn empty() -> ArgKind {
-        ArgKind::Arg("_".to_owned(), "_".to_owned())
-    }
-
-    /// Creates an `ArgKind` from the expected type of an
-    /// argument. It has no name (`_`) and an optional source span.
-    pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
-        match t.kind {
-            ty::Tuple(ref tys) => ArgKind::Tuple(
-                span,
-                tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
-            ),
-            _ => ArgKind::Arg("_".to_owned(), t.to_string()),
-        }
-    }
 }
 
 /// Suggest restricting a type param with a new bound.

From 4a75ef91f37dd0bd5267a852fa05ee0a5547a62b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 14 Jan 2020 10:29:13 -0800
Subject: [PATCH 11/25] fix error code index comment

---
 src/librustc_error_codes/error_codes/E0746.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md
index 538c9d720d71b..acf369d8e144f 100644
--- a/src/librustc_error_codes/error_codes/E0746.md
+++ b/src/librustc_error_codes/error_codes/E0746.md
@@ -12,7 +12,7 @@ impl T for S {
 }
 
 // Having the trait `T` as return type is invalid because bare traits do not
-have a statically known size:
+// have a statically known size:
 fn foo() -> dyn T {
     S(42)
 }

From 5b36c187dcbb8a4b6555fe046194f2b6deb74230 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 14 Jan 2020 13:18:06 -0800
Subject: [PATCH 12/25] review comments

---
 src/librustc/traits/error_reporting/mod.rs    |   2 +
 .../traits/error_reporting/suggestions.rs     | 243 +++++++++---------
 src/librustc/traits/mod.rs                    |  14 +-
 src/librustc/ty/error.rs                      |   4 +-
 src/librustc_typeck/check/coercion.rs         |  31 +--
 src/librustc_typeck/check/mod.rs              |  12 -
 .../coerce-expect-unsized-ascribed.stderr     |  14 +-
 .../into-iter-no-impls-length-33.stderr       |  14 +-
 src/test/ui/destructure-trait-ref.rs          |   2 -
 src/test/ui/destructure-trait-ref.stderr      |  10 +-
 src/test/ui/dst/dst-bad-assign-3.rs           |   2 +-
 src/test/ui/dst/dst-bad-assign-3.stderr       |   2 +-
 src/test/ui/dst/dst-bad-assign.rs             |   2 +-
 src/test/ui/dst/dst-bad-assign.stderr         |   2 +-
 src/test/ui/error-codes/E0746.stderr          |   8 +-
 ...n-trait-return-should-be-impl-trait.stderr |  38 +--
 src/test/ui/impl-trait/equality.stderr        |   2 +-
 src/test/ui/issues/issue-58344.stderr         |   4 +-
 .../lifetime-elision-return-type-trait.stderr |   2 +-
 .../feature-gate-never_type_fallback.stderr   |   2 +-
 ...type-err-cause-on-impl-trait-return.stderr |  12 +-
 ...e-57673-ice-on-deref-of-boxed-trait.stderr |   2 +-
 22 files changed, 206 insertions(+), 218 deletions(-)

diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs
index f8329124851b0..17d7b75a7f7d6 100644
--- a/src/librustc/traits/error_reporting/mod.rs
+++ b/src/librustc/traits/error_reporting/mod.rs
@@ -1412,6 +1412,8 @@ pub fn suggest_constraining_type_param(
     false
 }
 
+/// Collect all the returned expressions within the input expression.
+/// Used to point at the return spans when we want to suggest some change to them.
 struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
 
 impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index 389edfa071794..0a9747b631e87 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -4,6 +4,7 @@ use super::{
 };
 
 use crate::infer::InferCtxt;
+use crate::traits::object_safety::object_safety_violations;
 use crate::ty::TypeckTables;
 use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
@@ -543,6 +544,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
+    /// applicable and signal that the error has been expanded appropriately and needs to be
+    /// emitted.
     crate fn suggest_impl_trait(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -550,9 +554,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     ) -> bool {
-        if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() {
-        } else {
-            return false;
+        match obligation.cause.code.peel_derives() {
+            // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
+            ObligationCauseCode::SizedReturnType => {}
+            _ => return false,
         }
 
         let hir = self.tcx.hir();
@@ -565,12 +570,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let body = hir.body(*body_id);
             let trait_ref = self.resolve_vars_if_possible(trait_ref);
             let ty = trait_ref.skip_binder().self_ty();
-            if let ty::Dynamic(..) = ty.kind {
-            } else {
+            let is_object_safe;
+            match ty.kind {
+                ty::Dynamic(predicates, _) => {
+                    // The `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
+                    is_object_safe = predicates.principal_def_id().map_or(true, |def_id| {
+                        !object_safety_violations(self.tcx, def_id).is_empty()
+                    })
+                }
                 // We only want to suggest `impl Trait` to `dyn Trait`s.
                 // For example, `fn foo() -> str` needs to be filtered out.
-                return false;
+                _ => return false,
             }
+
+            let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
+                ret_ty
+            } else {
+                return false;
+            };
+
             // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
             // cases like `fn foo() -> (dyn Trait, i32) {}`.
             // Recursively look for `TraitObject` types and if there's only one, use that span to
@@ -583,122 +601,120 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
             let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
 
-            if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
-                let mut all_returns_conform_to_trait = true;
-                let mut all_returns_have_same_type = true;
-                let mut last_ty = None;
-                if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
-                    let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
-                    if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
-                        for predicate in predicates.iter() {
-                            for expr in &visitor.0 {
-                                if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                                    if let Some(ty) = last_ty {
-                                        all_returns_have_same_type &= ty == returned_ty;
-                                    }
-                                    last_ty = Some(returned_ty);
-
-                                    let param_env = ty::ParamEnv::empty();
-                                    let pred = predicate.with_self_ty(self.tcx, returned_ty);
-                                    let obligation =
-                                        Obligation::new(cause.clone(), param_env, pred);
-                                    all_returns_conform_to_trait &=
-                                        self.predicate_may_hold(&obligation);
-                                }
-                            }
-                        }
-                    }
-                } else {
-                    // We still want to verify whether all the return types conform to each other.
+            let mut all_returns_conform_to_trait = true;
+            let mut all_returns_have_same_type = true;
+            let mut last_ty = None;
+            if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
+                let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
+                let param_env = ty::ParamEnv::empty();
+                if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
                     for expr in &visitor.0 {
                         if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                            if let Some(ty) = last_ty {
-                                all_returns_have_same_type &= ty == returned_ty;
-                            }
+                            all_returns_have_same_type &=
+                                Some(returned_ty) == last_ty || last_ty.is_none();
                             last_ty = Some(returned_ty);
+                            for predicate in predicates.iter() {
+                                let pred = predicate.with_self_ty(self.tcx, returned_ty);
+                                let obl = Obligation::new(cause.clone(), param_env, pred);
+                                all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
+                            }
+                        }
+                    }
+                }
+            } else {
+                // We still want to verify whether all the return types conform to each other.
+                for expr in &visitor.0 {
+                    if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                        if let Some(ty) = last_ty {
+                            all_returns_have_same_type &= ty == returned_ty;
                         }
+                        last_ty = Some(returned_ty);
                     }
                 }
+            }
 
+            let (snippet, last_ty) =
                 if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
+                    // Verify that we're dealing with a return `dyn Trait`
                     ret_ty.span.overlaps(span),
                     &ret_ty.kind,
                     self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
+                    // If any of the return types does not conform to the trait, then we can't
+                    // suggest `impl Trait` nor trait objects, it is a type mismatch error.
                     all_returns_conform_to_trait,
                     last_ty,
                 ) {
-                    err.code = Some(error_code!(E0746));
-                    err.set_primary_message(
-                        "return type cannot have a bare trait because it must be `Sized`",
+                    (snippet, last_ty)
+                } else {
+                    return false;
+                };
+            err.code(error_code!(E0746));
+            err.set_primary_message("return type cannot have an unboxed trait object");
+            err.children.clear();
+            let impl_trait_msg = "for information on `impl Trait`, see \
+                <https://doc.rust-lang.org/book/ch10-02-traits.html\
+                #returning-types-that-implement-traits>";
+            let trait_obj_msg = "for information on trait objects, see \
+                <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
+                #using-trait-objects-that-allow-for-values-of-different-types>";
+            let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
+            let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
+            if all_returns_have_same_type {
+                // Suggest `-> impl Trait`.
+                err.span_suggestion(
+                    ret_ty.span,
+                    &format!(
+                        "return `impl {1}` instead, as all return paths are of type `{}`, \
+                         which implements `{1}`",
+                        last_ty, trait_obj,
+                    ),
+                    format!("impl {}", trait_obj),
+                    Applicability::MachineApplicable,
+                );
+                err.note(impl_trait_msg);
+            } else {
+                if is_object_safe {
+                    // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
+                    // Get all the return values and collect their span and suggestion.
+                    let mut suggestions = visitor
+                        .0
+                        .iter()
+                        .map(|expr| {
+                            (
+                                expr.span,
+                                format!(
+                                    "Box::new({})",
+                                    self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
+                                ),
+                            )
+                        })
+                        .collect::<Vec<_>>();
+                    // Add the suggestion for the return type.
+                    suggestions.push((
+                        ret_ty.span,
+                        format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
+                    ));
+                    err.multipart_suggestion(
+                        "return a trait object instead",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
                     );
-                    err.children.clear();
-                    let impl_trait_msg = "for information on `impl Trait`, see \
-                        <https://doc.rust-lang.org/book/ch10-02-traits.html\
-                        #returning-types-that-implement-traits>";
-                    let trait_obj_msg = "for information on trait objects, see \
-                        <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
-                        #using-trait-objects-that-allow-for-values-of-different-types>";
-                    let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
-                    let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
-                    if all_returns_have_same_type {
-                        err.span_suggestion(
-                            ret_ty.span,
-                            &format!(
-                                "you can use the `impl Trait` feature \
-                                 in the return type because all the return paths are of type \
-                                 `{}`, which implements `dyn {}`",
-                                last_ty, trait_obj,
-                            ),
-                            format!("impl {}", trait_obj),
-                            Applicability::MachineApplicable,
-                        );
-                        err.note(impl_trait_msg);
-                    } else {
-                        let mut suggestions = visitor
-                            .0
-                            .iter()
-                            .map(|expr| {
-                                (
-                                    expr.span,
-                                    format!(
-                                        "Box::new({})",
-                                        self.tcx
-                                            .sess
-                                            .source_map()
-                                            .span_to_snippet(expr.span)
-                                            .unwrap()
-                                    ),
-                                )
-                            })
-                            .collect::<Vec<_>>();
-                        suggestions.push((
-                            ret_ty.span,
-                            format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
-                        ));
-                        err.multipart_suggestion(
-                            "if the performance implications are acceptable, you can return a \
-                             trait object",
-                            suggestions,
-                            Applicability::MaybeIncorrect,
-                        );
-                        err.span_help(
-                            visitor.0.iter().map(|expr| expr.span).collect::<Vec<_>>(),
-                            &format!(
-                                "if all the returned values were of the same type you could use \
-                                 `impl {}` as the return type",
-                                trait_obj,
-                            ),
-                        );
-                        err.help(
-                            "alternatively, you can always create a new `enum` with a variant \
-                             for each returned type",
-                        );
-                        err.note(impl_trait_msg);
-                        err.note(trait_obj_msg);
-                    }
-                    return true;
+                } else {
+                    err.note(&format!(
+                        "if trait `{}` was object safe, you could return a trait object",
+                        trait_obj,
+                    ));
                 }
+                err.note(&format!(
+                    "if all the returned values were of the same type you could use \
+                     `impl {}` as the return type",
+                    trait_obj,
+                ));
+                err.note(impl_trait_msg);
+                err.note(trait_obj_msg);
+                err.note("you can create a new `enum` with a variant for each returned type");
             }
+            return true;
         }
         false
     }
@@ -708,9 +724,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) {
-        if let ObligationCauseCode::SizedReturnType = obligation.cause.code.peel_derives() {
-        } else {
-            return;
+        match obligation.cause.code.peel_derives() {
+            ObligationCauseCode::SizedReturnType => {}
+            _ => return,
         }
 
         let hir = self.tcx.hir();
@@ -726,10 +742,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
             for expr in &visitor.0 {
                 if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                    err.span_label(
-                        expr.span,
-                        &format!("this returned value is of type `{}`", returned_ty),
-                    );
+                    let ty = self.resolve_vars_if_possible(&returned_ty);
+                    err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
                 }
             }
         }
@@ -1685,9 +1699,8 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
     }
 
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-        match ex.kind {
-            hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
-            _ => {}
+        if let hir::ExprKind::Ret(Some(ex)) = ex.kind {
+            self.0.push(ex);
         }
         hir::intravisit::walk_expr(self, ex);
     }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index f68711c06205b..b4998d4486f09 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -155,8 +155,8 @@ pub struct ObligationCause<'tcx> {
     pub code: ObligationCauseCode<'tcx>,
 }
 
-impl<'tcx> ObligationCause<'tcx> {
-    pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
+impl ObligationCause<'_> {
+    pub fn span(&self, tcx: TyCtxt<'_>) -> Span {
         match self.code {
             ObligationCauseCode::CompareImplMethodObligation { .. }
             | ObligationCauseCode::MainFunctionType
@@ -1172,13 +1172,13 @@ impl<'tcx> ObligationCause<'tcx> {
 }
 
 impl<'tcx> ObligationCauseCode<'tcx> {
+    // Return the base obligation, ignoring derived obligations.
     pub fn peel_derives(&self) -> &Self {
-        match self {
-            BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) => {
-                cause.parent_code.peel_derives()
-            }
-            _ => self,
+        let mut base_cause = self;
+        while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause {
+            base_cause = &cause.parent_code;
         }
+        base_cause
     }
 }
 
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index f7612874e05b6..217ca0ca3f6f5 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -244,9 +244,9 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(ref inner, ..) => {
                 if let Some(principal) = inner.principal() {
-                    format!("trait `{}`", tcx.def_path_str(principal.def_id())).into()
+                    format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
                 } else {
-                    "trait".into()
+                    "trait object".into()
                 }
             }
             ty::Closure(..) => "closure".into(),
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 77f16fb79141d..66499b1753fdd 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -50,6 +50,7 @@
 //! sort of a minor point so I've opted to leave it for later -- after all,
 //! we may want to adjust precisely when coercions occur.
 
+use crate::astconv::AstConv;
 use crate::check::{FnCtxt, Needs};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::infer::{Coercion, InferOk, InferResult};
@@ -1245,7 +1246,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             expression.map(|expr| (expr, blk_id)),
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            unsized_return = fcx.is_unsized_return(blk_id);
+                            unsized_return = self.is_return_ty_unsized(fcx, blk_id);
                         }
                     }
                     ObligationCauseCode::ReturnValue(id) => {
@@ -1260,7 +1261,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         );
                         if !fcx.tcx.features().unsized_locals {
                             let id = fcx.tcx.hir().get_parent_node(id);
-                            unsized_return = fcx.is_unsized_return(id);
+                            unsized_return = self.is_return_ty_unsized(fcx, id);
                         }
                     }
                     _ => {
@@ -1290,15 +1291,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
                     .is_some();
 
-                if unsized_return {
-                    fcx.tcx.sess.delay_span_bug(
-                        cause.span,
-                        &format!(
-                            "elided E0308 in favor of more detailed E0277 or E0746: {:?}",
-                            cause.code
-                        ),
-                    );
-                }
                 err.emit_unless(assign_to_bool || unsized_return);
 
                 self.final_ty = Some(fcx.tcx.types.err);
@@ -1365,10 +1357,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 "...is found to be `{}` here",
                 fcx.resolve_vars_with_obligations(expected),
             ));
-            err.note(
-                "`impl Trait` as a return type requires that all the returned values must have \
-                 the same type",
-            );
+            err.note("to return `impl Trait`, all returned values must be of the same type");
             let snippet = fcx
                 .tcx
                 .sess
@@ -1397,6 +1386,18 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         err
     }
 
+    fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
+        if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) {
+            if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
+                let ty = AstConv::ast_ty_to_ty(fcx, ty);
+                if let ty::Dynamic(..) = ty.kind {
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
         if let Some(final_ty) = self.final_ty {
             final_ty
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8f531ea6199e1..baf9ae1ac2911 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4964,18 +4964,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn is_unsized_return(&self, blk_id: hir::HirId) -> bool {
-        if let Some((fn_decl, _)) = self.get_fn_decl(blk_id) {
-            if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
-                let ty = AstConv::ast_ty_to_ty(self, ty);
-                if let ty::Dynamic(..) = ty.kind {
-                    return true;
-                }
-            }
-        }
-        false
-    }
-
     /// A possible error is to forget to add a return type that is needed:
     ///
     /// ```
diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
index 303d83d342625..44e5c6a99f727 100644
--- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
+++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -29,7 +29,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:13:13
    |
 LL |     let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>;
-   |             ^^^^^^^^^^^^^^^^^^^^^ expected trait `std::ops::Fn`, found closure
+   |             ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure
    |
    = note: expected struct `std::boxed::Box<dyn std::ops::Fn(i32) -> u8>`
               found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>`
@@ -38,7 +38,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:14:13
    |
 LL |     let _ = box if true { false } else { true }: Box<dyn Debug>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::fmt::Debug`, found `bool`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool`
    |
    = note: expected struct `std::boxed::Box<dyn std::fmt::Debug>`
               found struct `std::boxed::Box<bool>`
@@ -47,7 +47,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:15:13
    |
 LL |     let _ = box match true { true => 'a', false => 'b' }: Box<dyn Debug>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::fmt::Debug`, found `char`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char`
    |
    = note: expected struct `std::boxed::Box<dyn std::fmt::Debug>`
               found struct `std::boxed::Box<char>`
@@ -83,7 +83,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:21:13
    |
 LL |     let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _;
-   |             ^^^^^^^^^^^^^^^^^^ expected trait `std::ops::Fn`, found closure
+   |             ^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure
    |
    = note: expected reference `&dyn std::ops::Fn(i32) -> u8`
               found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:29]`
@@ -92,7 +92,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:22:13
    |
 LL |     let _ = &if true { false } else { true }: &dyn Debug;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::fmt::Debug`, found `bool`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool`
    |
    = note: expected reference `&dyn std::fmt::Debug`
               found reference `&bool`
@@ -101,7 +101,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:23:13
    |
 LL |     let _ = &match true { true => 'a', false => 'b' }: &dyn Debug;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::fmt::Debug`, found `char`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char`
    |
    = note: expected reference `&dyn std::fmt::Debug`
               found reference `&char`
@@ -119,7 +119,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:26:13
    |
 LL |     let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::ops::Fn`, found closure
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure
    |
    = note: expected struct `std::boxed::Box<dyn std::ops::Fn(i32) -> _>`
               found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>`
diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
index e615e10bd5f5f..4869f48363447 100644
--- a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
@@ -13,7 +13,7 @@ LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -33,7 +33,7 @@ LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -53,7 +53,7 @@ LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -73,7 +73,7 @@ LL | pub fn no_fused_iterator() -> impl FusedIterator {
    |                               ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -93,7 +93,7 @@ LL | pub fn no_trusted_len() -> impl TrustedLen {
    |                            ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -113,7 +113,7 @@ LL | pub fn no_clone() -> impl Clone {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
@@ -133,7 +133,7 @@ LL | pub fn no_debug() -> impl Debug {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<_, _: usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
    |
    = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33usize>`
    = note: the return type of a function must have a statically known size
diff --git a/src/test/ui/destructure-trait-ref.rs b/src/test/ui/destructure-trait-ref.rs
index fb92196b2bd56..34e7cad935aeb 100644
--- a/src/test/ui/destructure-trait-ref.rs
+++ b/src/test/ui/destructure-trait-ref.rs
@@ -33,12 +33,10 @@ fn main() {
     //~^ ERROR mismatched types
     //~| expected trait object `dyn T`
     //~| found reference `&_`
-    //~| expected trait `T`, found reference
     let &&&x = &(&1isize as &dyn T);
     //~^ ERROR mismatched types
     //~| expected trait object `dyn T`
     //~| found reference `&_`
-    //~| expected trait `T`, found reference
     let box box x = box 1isize as Box<dyn T>;
     //~^ ERROR mismatched types
     //~| expected trait object `dyn T`
diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr
index c78166f411d28..f99bf2ffdc9d4 100644
--- a/src/test/ui/destructure-trait-ref.stderr
+++ b/src/test/ui/destructure-trait-ref.stderr
@@ -22,31 +22,31 @@ error[E0308]: mismatched types
 LL |     let &&x = &1isize as &dyn T;
    |          ^^
    |          |
-   |          expected trait `T`, found reference
+   |          expected trait object `dyn T`, found reference
    |          help: you can probably remove the explicit borrow: `x`
    |
    = note: expected trait object `dyn T`
                  found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/destructure-trait-ref.rs:37:11
+  --> $DIR/destructure-trait-ref.rs:36:11
    |
 LL |     let &&&x = &(&1isize as &dyn T);
    |           ^^
    |           |
-   |           expected trait `T`, found reference
+   |           expected trait object `dyn T`, found reference
    |           help: you can probably remove the explicit borrow: `x`
    |
    = note: expected trait object `dyn T`
                  found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/destructure-trait-ref.rs:42:13
+  --> $DIR/destructure-trait-ref.rs:40:13
    |
 LL |     let box box x = box 1isize as Box<dyn T>;
    |             ^^^^^   ------------------------ this expression has type `std::boxed::Box<dyn T>`
    |             |
-   |             expected trait `T`, found struct `std::boxed::Box`
+   |             expected trait object `dyn T`, found struct `std::boxed::Box`
    |
    = note: expected trait object `dyn T`
                     found struct `std::boxed::Box<_>`
diff --git a/src/test/ui/dst/dst-bad-assign-3.rs b/src/test/ui/dst/dst-bad-assign-3.rs
index e3b621b909a0c..d05b3937c998c 100644
--- a/src/test/ui/dst/dst-bad-assign-3.rs
+++ b/src/test/ui/dst/dst-bad-assign-3.rs
@@ -32,7 +32,7 @@ pub fn main() {
     let z: Box<dyn ToBar> = Box::new(Bar1 {f: 36});
     f5.2 = Bar1 {f: 36};
     //~^ ERROR mismatched types
-    //~| expected trait `ToBar`, found struct `Bar1`
+    //~| expected trait object `dyn ToBar`, found struct `Bar1`
     //~| expected trait object `dyn ToBar`
     //~| found struct `Bar1`
     //~| ERROR the size for values of type
diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr
index dc03f38e10387..0b6f9df2d83ee 100644
--- a/src/test/ui/dst/dst-bad-assign-3.stderr
+++ b/src/test/ui/dst/dst-bad-assign-3.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-assign-3.rs:33:12
    |
 LL |     f5.2 = Bar1 {f: 36};
-   |            ^^^^^^^^^^^^ expected trait `ToBar`, found struct `Bar1`
+   |            ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
diff --git a/src/test/ui/dst/dst-bad-assign.rs b/src/test/ui/dst/dst-bad-assign.rs
index ed94242f5bfd0..496e01ae00532 100644
--- a/src/test/ui/dst/dst-bad-assign.rs
+++ b/src/test/ui/dst/dst-bad-assign.rs
@@ -34,7 +34,7 @@ pub fn main() {
     let z: Box<dyn ToBar> = Box::new(Bar1 {f: 36});
     f5.ptr = Bar1 {f: 36};
     //~^ ERROR mismatched types
-    //~| expected trait `ToBar`, found struct `Bar1`
+    //~| expected trait object `dyn ToBar`, found struct `Bar1`
     //~| expected trait object `dyn ToBar`
     //~| found struct `Bar1`
     //~| ERROR the size for values of type
diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr
index 8031f162482e3..434c460759fb4 100644
--- a/src/test/ui/dst/dst-bad-assign.stderr
+++ b/src/test/ui/dst/dst-bad-assign.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-assign.rs:35:14
    |
 LL |     f5.ptr = Bar1 {f: 36};
-   |              ^^^^^^^^^^^^ expected trait `ToBar`, found struct `Bar1`
+   |              ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr
index 1c88ce64749ae..e7a8fd304cabe 100644
--- a/src/test/ui/error-codes/E0746.stderr
+++ b/src/test/ui/error-codes/E0746.stderr
@@ -1,23 +1,23 @@
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/E0746.rs:8:13
    |
 LL | fn foo() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+help: return `impl Trait` instead, as all return paths are of type `Struct`, which implements `Trait`
    |
 LL | fn foo() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/E0746.rs:11:13
    |
 LL | fn bar() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: you can use the `impl Trait` feature in the return type because all the return paths are of type `{integer}`, which implements `dyn Trait`
+help: return `impl Trait` instead, as all return paths are of type `{integer}`, which implements `Trait`
    |
 LL | fn bar() -> impl Trait {
    |             ^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index ff7438e9affc1..3d0707c091644 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:35
    |
 LL | fn fuz() -> (usize, Trait) { (42, Struct) }
-   |                                   ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |                                   ^^^^^^ expected trait object `dyn Trait`, found struct `Struct`
    |
    = note: expected trait object `(dyn Trait + 'static)`
                     found struct `Struct`
@@ -24,7 +24,7 @@ error[E0308]: mismatched types
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:39
    |
 LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
-   |                                       ^^^^^^ expected trait `Trait`, found struct `Struct`
+   |                                       ^^^^^^ expected trait object `dyn Trait`, found struct `Struct`
    |
    = note: expected trait object `(dyn Trait + 'static)`
                     found struct `Struct`
@@ -42,26 +42,26 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13
    |
 LL | fn bap() -> Trait { Struct }
    |             ^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+help: return `impl Trait` instead, as all return paths are of type `Struct`, which implements `Trait`
    |
 LL | fn bap() -> impl Trait { Struct }
    |             ^^^^^^^^^^
 
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
    |
 LL | fn ban() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: you can use the `impl Trait` feature in the return type because all the return paths are of type `Struct`, which implements `dyn Trait`
+help: return `impl Trait` instead, as all return paths are of type `Struct`, which implements `Trait`
    |
 LL | fn ban() -> impl Trait { Struct }
    |             ^^^^^^^^^^
@@ -76,40 +76,26 @@ LL | fn bak() -> dyn Trait { unimplemented!() }
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the return type of a function must have a statically known size
 
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
    |
 LL | fn bal() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: if all the returned values were of the same type you could use `impl Trait` as the return type
-  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:5
-   |
-LL |         return Struct;
-   |                ^^^^^^
-LL |     }
-LL |     42
-   |     ^^
-   = help: alternatively, you can always create a new `enum` with a variant for each returned type
+   = note: if trait `Trait` was object safe, you could return a trait object
+   = note: if all the returned values were of the same type you could use `impl Trait` as the return type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
-help: if the performance implications are acceptable, you can return a trait object
-   |
-LL | fn bal() -> Box<dyn Trait> {
-LL |     if true {
-LL |         return Box::new(Struct);
-LL |     }
-LL |     Box::new(42)
-   |
+   = note: you can create a new `enum` with a variant for each returned type
 
-error[E0746]: return type cannot have a bare trait because it must be `Sized`
+error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13
    |
 LL | fn bat() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: you can use the `impl Trait` feature in the return type because all the return paths are of type `{integer}`, which implements `dyn Trait`
+help: return `impl Trait` instead, as all return paths are of type `{integer}`, which implements `Trait`
    |
 LL | fn bat() -> impl Trait {
    |             ^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index 215b6d52918ab..be8653d1689f8 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -10,7 +10,7 @@ LL |     }
 LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn Foo>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr
index 9b07dbd7ab69c..e0c196e518ba3 100644
--- a/src/test/ui/issues/issue-58344.stderr
+++ b/src/test/ui/issues/issue-58344.stderr
@@ -5,7 +5,7 @@ LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
 ...
 LL |     add_generic(value, 1u32)
-   |     ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>`
+   |     ------------------------ this returned value is of type `Either<impl Trait<<u32 as std::ops::Add>::Output>, impl Trait<<u32 as std::ops::Add>::Output>>`
    |
    = note: the return type of a function must have a statically known size
 
@@ -16,7 +16,7 @@ LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
 ...
 LL |     add_generic(value, 1u32)
-   |     ------------------------ this returned value is of type `Either<impl Trait<<_ as std::ops::Add<_>>::Output>, impl Trait<<_ as std::ops::Add<_>>::Output>>`
+   |     ------------------------ this returned value is of type `Either<impl Trait<<u32 as std::ops::Add>::Output>, impl Trait<<u32 as std::ops::Add>::Output>>`
    |
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index 49fa11c35aef8..e43fb6d0edfb9 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -5,7 +5,7 @@ LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
 LL |
 LL |     Ok(())
-   |     ------ this returned value is of type `std::result::Result<_, _>`
+   |     ------ this returned value is of type `std::result::Result<(), _>`
    |
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
index 88bfed2b54742..77288f1badac5 100644
--- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -5,7 +5,7 @@ LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^ the trait `T` is not implemented for `()`
 LL |
 LL |     panic!()
-   |     -------- this returned value is of type `_`
+   |     -------- this returned value is of type `()`
    |
    = note: the return type of a function must have a statically known size
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
index 9db5250e4d876..2c0425e718abc 100644
--- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -10,7 +10,7 @@ LL |     }
 LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
@@ -27,7 +27,7 @@ LL |     } else {
 LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
@@ -44,7 +44,7 @@ LL |     } else {
 LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
@@ -73,7 +73,7 @@ LL |         0 => return 0i32,
 LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
@@ -92,7 +92,7 @@ LL | |         _ => 2u32,
 LL | |     }
    | |_____^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
@@ -109,7 +109,7 @@ LL |             return 0i32;
 LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
    |
-   = note: `impl Trait` as a return type requires that all the returned values must have the same type
+   = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
index 14c09ade7dde3..a656b20c23ec3 100644
--- a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
+++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL | fn ice(x: Box<dyn Iterator<Item=()>>) {
    |                                       - possibly return type missing here?
 LL |     *x
-   |     ^^ expected `()`, found trait `std::iter::Iterator`
+   |     ^^ expected `()`, found trait object `dyn std::iter::Iterator`
    |
    = note: expected unit type `()`
            found trait object `(dyn std::iter::Iterator<Item = ()> + 'static)`

From 509cb33dbcdb631625288f72c359a35dde6524b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 14 Jan 2020 14:49:30 -0800
Subject: [PATCH 13/25] review comments

---
 src/librustc/traits/error_reporting/suggestions.rs       | 9 +++------
 src/librustc_typeck/check/coercion.rs                    | 1 +
 src/test/ui/impl-trait/equality.stderr                   | 1 +
 .../point-to-type-err-cause-on-impl-trait-return.stderr  | 6 ++++++
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index 0a9747b631e87..c2f562b4bc7b2 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -624,12 +624,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             } else {
                 // We still want to verify whether all the return types conform to each other.
                 for expr in &visitor.0 {
-                    if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                        if let Some(ty) = last_ty {
-                            all_returns_have_same_type &= ty == returned_ty;
-                        }
-                        last_ty = Some(returned_ty);
-                    }
+                    let returned_ty = tables.node_type_opt(expr.hir_id);
+                    all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
+                    last_ty = returned_ty;
                 }
             }
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 66499b1753fdd..8aa2cb5034224 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1372,6 +1372,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     &snippet[5..]
                 ));
             }
+            err.help("alternatively, create a new `enum` with a variant for each returned type");
             let impl_trait_msg = "for information on `impl Trait`, see \
                 <https://doc.rust-lang.org/book/ch10-02-traits.html\
                 #returning-types-that-implement-traits>";
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index be8653d1689f8..ceb32dd4cd33e 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -12,6 +12,7 @@ LL |     0_u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn Foo>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
index 2c0425e718abc..87daab5ca7a22 100644
--- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -12,6 +12,7 @@ LL |     1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
@@ -29,6 +30,7 @@ LL |         return 1u32;
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
@@ -46,6 +48,7 @@ LL |         1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
@@ -75,6 +78,7 @@ LL |         _ => 1u32,
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
@@ -94,6 +98,7 @@ LL | |     }
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 
@@ -111,6 +116,7 @@ LL |             1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
 

From c305ac31c09fdd5078fa0e69e718b4da10d9e354 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 15 Jan 2020 09:55:56 -0800
Subject: [PATCH 14/25] Fix error index test

---
 src/librustc_error_codes/error_codes/E0746.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md
index acf369d8e144f..2df27bcf0bf09 100644
--- a/src/librustc_error_codes/error_codes/E0746.md
+++ b/src/librustc_error_codes/error_codes/E0746.md
@@ -2,7 +2,8 @@ Return types cannot be `dyn Trait`s as they must be `Sized`.
 
 Erroneous code example:
 
-```compile_fail,E0746
+```compile_fail,E0277
+# // FIXME: after E0746 is in beta, change the above
 trait T {
     fn bar(&self);
 }

From d7a62124018ce8438caeedca203d39997f130b49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 15 Jan 2020 11:14:05 -0800
Subject: [PATCH 15/25] review comments

---
 src/librustc/traits/error_reporting/mod.rs    |  32 ---
 .../traits/error_reporting/suggestions.rs     | 270 +++++++++---------
 src/librustc/traits/mod.rs                    |   2 +-
 src/librustc_error_codes/error_codes/E0746.md |  10 +-
 src/librustc_typeck/check/coercion.rs         |  67 +++--
 ...n-trait-return-should-be-impl-trait.stderr |  11 +-
 src/test/ui/impl-trait/equality.stderr        |   4 +-
 ...type-err-cause-on-impl-trait-return.stderr |  24 +-
 8 files changed, 204 insertions(+), 216 deletions(-)

diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs
index 17d7b75a7f7d6..db3173989ac60 100644
--- a/src/librustc/traits/error_reporting/mod.rs
+++ b/src/librustc/traits/error_reporting/mod.rs
@@ -25,7 +25,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::intravisit::Visitor;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{ExpnKind, Span, DUMMY_SP};
 use std::fmt;
@@ -1411,34 +1410,3 @@ pub fn suggest_constraining_type_param(
     }
     false
 }
-
-/// Collect all the returned expressions within the input expression.
-/// Used to point at the return spans when we want to suggest some change to them.
-struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
-
-impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
-    type Map = rustc::hir::map::Map<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-        match ex.kind {
-            hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
-            _ => {}
-        }
-        hir::intravisit::walk_expr(self, ex);
-    }
-
-    fn visit_body(&mut self, body: &'v hir::Body<'v>) {
-        if body.generator_kind().is_none() {
-            if let hir::ExprKind::Block(block, None) = body.value.kind {
-                if let Some(expr) = block.expr {
-                    self.0.push(expr);
-                }
-            }
-        }
-        hir::intravisit::walk_body(self, body);
-    }
-}
diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index c2f562b4bc7b2..7c1b1041c34c3 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -563,157 +563,159 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let hir = self.tcx.hir();
         let parent_node = hir.get_parent_node(obligation.cause.body_id);
         let node = hir.find(parent_node);
-        if let Some(hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(sig, _, body_id), ..
+        let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(sig, _, body_id),
+            ..
         })) = node
         {
-            let body = hir.body(*body_id);
-            let trait_ref = self.resolve_vars_if_possible(trait_ref);
-            let ty = trait_ref.skip_binder().self_ty();
-            let is_object_safe;
-            match ty.kind {
-                ty::Dynamic(predicates, _) => {
-                    // The `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
-                    is_object_safe = predicates.principal_def_id().map_or(true, |def_id| {
-                        !object_safety_violations(self.tcx, def_id).is_empty()
-                    })
-                }
-                // We only want to suggest `impl Trait` to `dyn Trait`s.
-                // For example, `fn foo() -> str` needs to be filtered out.
-                _ => return false,
+            (sig, body_id)
+        } else {
+            return false;
+        };
+        let body = hir.body(*body_id);
+        let trait_ref = self.resolve_vars_if_possible(trait_ref);
+        let ty = trait_ref.skip_binder().self_ty();
+        let is_object_safe = match ty.kind {
+            ty::Dynamic(predicates, _) => {
+                // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
+                predicates
+                    .principal_def_id()
+                    .map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty())
             }
+            // We only want to suggest `impl Trait` to `dyn Trait`s.
+            // For example, `fn foo() -> str` needs to be filtered out.
+            _ => return false,
+        };
 
-            let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
-                ret_ty
-            } else {
-                return false;
-            };
-
-            // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
-            // cases like `fn foo() -> (dyn Trait, i32) {}`.
-            // Recursively look for `TraitObject` types and if there's only one, use that span to
-            // suggest `impl Trait`.
-
-            // Visit to make sure there's a single `return` type to suggest `impl Trait`,
-            // otherwise suggest using `Box<dyn Trait>` or an enum.
-            let mut visitor = ReturnsVisitor(vec![]);
-            visitor.visit_body(&body);
-
-            let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+        let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
+            ret_ty
+        } else {
+            return false;
+        };
 
-            let mut all_returns_conform_to_trait = true;
-            let mut all_returns_have_same_type = true;
-            let mut last_ty = None;
-            if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
-                let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
-                let param_env = ty::ParamEnv::empty();
-                if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
-                    for expr in &visitor.0 {
-                        if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                            all_returns_have_same_type &=
-                                Some(returned_ty) == last_ty || last_ty.is_none();
-                            last_ty = Some(returned_ty);
-                            for predicate in predicates.iter() {
-                                let pred = predicate.with_self_ty(self.tcx, returned_ty);
-                                let obl = Obligation::new(cause.clone(), param_env, pred);
-                                all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
-                            }
+        // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
+        // cases like `fn foo() -> (dyn Trait, i32) {}`.
+        // Recursively look for `TraitObject` types and if there's only one, use that span to
+        // suggest `impl Trait`.
+
+        // Visit to make sure there's a single `return` type to suggest `impl Trait`,
+        // otherwise suggest using `Box<dyn Trait>` or an enum.
+        let mut visitor = ReturnsVisitor(vec![]);
+        visitor.visit_body(&body);
+
+        let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+
+        let mut all_returns_conform_to_trait = true;
+        let mut all_returns_have_same_type = true;
+        let mut last_ty = None;
+        if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
+            let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
+            let param_env = ty::ParamEnv::empty();
+            if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
+                for expr in &visitor.0 {
+                    if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                        all_returns_have_same_type &=
+                            Some(returned_ty) == last_ty || last_ty.is_none();
+                        last_ty = Some(returned_ty);
+                        for predicate in predicates.iter() {
+                            let pred = predicate.with_self_ty(self.tcx, returned_ty);
+                            let obl = Obligation::new(cause.clone(), param_env, pred);
+                            all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
                         }
                     }
                 }
-            } else {
-                // We still want to verify whether all the return types conform to each other.
-                for expr in &visitor.0 {
-                    let returned_ty = tables.node_type_opt(expr.hir_id);
-                    all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
-                    last_ty = returned_ty;
-                }
             }
+        } else {
+            // We still want to verify whether all the return types conform to each other.
+            for expr in &visitor.0 {
+                let returned_ty = tables.node_type_opt(expr.hir_id);
+                all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
+                last_ty = returned_ty;
+            }
+        }
 
-            let (snippet, last_ty) =
-                if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
-                    // Verify that we're dealing with a return `dyn Trait`
-                    ret_ty.span.overlaps(span),
-                    &ret_ty.kind,
-                    self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
-                    // If any of the return types does not conform to the trait, then we can't
-                    // suggest `impl Trait` nor trait objects, it is a type mismatch error.
-                    all_returns_conform_to_trait,
-                    last_ty,
-                ) {
-                    (snippet, last_ty)
-                } else {
-                    return false;
-                };
-            err.code(error_code!(E0746));
-            err.set_primary_message("return type cannot have an unboxed trait object");
-            err.children.clear();
-            let impl_trait_msg = "for information on `impl Trait`, see \
-                <https://doc.rust-lang.org/book/ch10-02-traits.html\
-                #returning-types-that-implement-traits>";
-            let trait_obj_msg = "for information on trait objects, see \
-                <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
-                #using-trait-objects-that-allow-for-values-of-different-types>";
-            let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
-            let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
-            if all_returns_have_same_type {
-                // Suggest `-> impl Trait`.
-                err.span_suggestion(
+        let (snippet, last_ty) =
+            if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
+                // Verify that we're dealing with a return `dyn Trait`
+                ret_ty.span.overlaps(span),
+                &ret_ty.kind,
+                self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
+                // If any of the return types does not conform to the trait, then we can't
+                // suggest `impl Trait` nor trait objects, it is a type mismatch error.
+                all_returns_conform_to_trait,
+                last_ty,
+            ) {
+                (snippet, last_ty)
+            } else {
+                return false;
+            };
+        err.code(error_code!(E0746));
+        err.set_primary_message("return type cannot have an unboxed trait object");
+        err.children.clear();
+        let impl_trait_msg = "for information on `impl Trait`, see \
+            <https://doc.rust-lang.org/book/ch10-02-traits.html\
+            #returning-types-that-implement-traits>";
+        let trait_obj_msg = "for information on trait objects, see \
+            <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
+            #using-trait-objects-that-allow-for-values-of-different-types>";
+        let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
+        let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
+        if all_returns_have_same_type {
+            // Suggest `-> impl Trait`.
+            err.span_suggestion(
+                ret_ty.span,
+                &format!(
+                    "return `impl {1}` instead, as all return paths are of type `{}`, \
+                        which implements `{1}`",
+                    last_ty, trait_obj,
+                ),
+                format!("impl {}", trait_obj),
+                Applicability::MachineApplicable,
+            );
+            err.note(impl_trait_msg);
+        } else {
+            if is_object_safe {
+                // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
+                // Get all the return values and collect their span and suggestion.
+                let mut suggestions = visitor
+                    .0
+                    .iter()
+                    .map(|expr| {
+                        (
+                            expr.span,
+                            format!(
+                                "Box::new({})",
+                                self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
+                            ),
+                        )
+                    })
+                    .collect::<Vec<_>>();
+                // Add the suggestion for the return type.
+                suggestions.push((
                     ret_ty.span,
-                    &format!(
-                        "return `impl {1}` instead, as all return paths are of type `{}`, \
-                         which implements `{1}`",
-                        last_ty, trait_obj,
-                    ),
-                    format!("impl {}", trait_obj),
-                    Applicability::MachineApplicable,
+                    format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
+                ));
+                err.multipart_suggestion(
+                        "return a trait object instead",
+                    suggestions,
+                    Applicability::MaybeIncorrect,
                 );
-                err.note(impl_trait_msg);
             } else {
-                if is_object_safe {
-                    // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
-                    // Get all the return values and collect their span and suggestion.
-                    let mut suggestions = visitor
-                        .0
-                        .iter()
-                        .map(|expr| {
-                            (
-                                expr.span,
-                                format!(
-                                    "Box::new({})",
-                                    self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
-                                ),
-                            )
-                        })
-                        .collect::<Vec<_>>();
-                    // Add the suggestion for the return type.
-                    suggestions.push((
-                        ret_ty.span,
-                        format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
-                    ));
-                    err.multipart_suggestion(
-                        "return a trait object instead",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    err.note(&format!(
-                        "if trait `{}` was object safe, you could return a trait object",
-                        trait_obj,
-                    ));
-                }
                 err.note(&format!(
-                    "if all the returned values were of the same type you could use \
-                     `impl {}` as the return type",
+                    "if trait `{}` was object safe, you could return a trait object",
                     trait_obj,
                 ));
-                err.note(impl_trait_msg);
-                err.note(trait_obj_msg);
-                err.note("you can create a new `enum` with a variant for each returned type");
             }
-            return true;
+            err.note(trait_obj_msg);
+            err.note(&format!(
+                "if all the returned values were of the same type you could use \
+                    `impl {}` as the return type",
+                trait_obj,
+            ));
+            err.note(impl_trait_msg);
+            err.note("you can create a new `enum` with a variant for each returned type");
         }
-        false
+        true
     }
 
     crate fn point_at_returns_when_relevant(
@@ -1686,6 +1688,8 @@ pub fn suggest_constraining_type_param(
     false
 }
 
+/// Collect all the returned expressions within the input expression.
+/// Used to point at the return spans when we want to suggest some change to them.
 struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
 
 impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b4998d4486f09..2e5da2b038254 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -1171,7 +1171,7 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 }
 
-impl<'tcx> ObligationCauseCode<'tcx> {
+impl ObligationCauseCode<'_> {
     // Return the base obligation, ignoring derived obligations.
     pub fn peel_derives(&self) -> &Self {
         let mut base_cause = self;
diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md
index 2df27bcf0bf09..041061f3380c1 100644
--- a/src/librustc_error_codes/error_codes/E0746.md
+++ b/src/librustc_error_codes/error_codes/E0746.md
@@ -12,8 +12,8 @@ impl T for S {
     fn bar(&self) {}
 }
 
-// Having the trait `T` as return type is invalid because bare traits do not
-// have a statically known size:
+// Having the trait `T` as return type is invalid because
+// bare trait objects do not have a statically known size:
 fn foo() -> dyn T {
     S(42)
 }
@@ -32,15 +32,15 @@ If there is a single type involved, you can use [`impl Trait`]:
 #     fn bar(&self) {}
 # }
 // The compiler will select `S(usize)` as the materialized return type of this
-// function, but callers will only be able to access associated items from `T`.
+// function, but callers will only know that the return type implements `T`.
 fn foo() -> impl T {
     S(42)
 }
 ```
 
 If there are multiple types involved, the only way you care to interact with
-them is through the trait's interface and having to rely on dynamic dispatch is
-acceptable, then you can use [trait objects] with `Box`, or other container
+them is through the trait's interface, and having to rely on dynamic dispatch
+is acceptable, then you can use [trait objects] with `Box`, or other container
 types like `Rc` or `Arc`:
 
 ```
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 8aa2cb5034224..768e532fa3b91 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -68,7 +68,7 @@ use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_span;
+use rustc_span::{self, Span};
 use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 use smallvec::{smallvec, SmallVec};
@@ -1352,39 +1352,48 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             }
         }
         if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
-            err.span_label(return_sp, "expected because this return type...");
-            err.span_label( *sp, format!(
-                "...is found to be `{}` here",
-                fcx.resolve_vars_with_obligations(expected),
-            ));
-            err.note("to return `impl Trait`, all returned values must be of the same type");
-            let snippet = fcx
-                .tcx
-                .sess
-                .source_map()
-                .span_to_snippet(return_sp)
-                .unwrap_or_else(|_| "dyn Trait".to_string());
-            let mut snippet_iter = snippet.split_whitespace();
-            let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
-            if has_impl {
-                err.help(&format!(
-                    "you can instead return a trait object using `Box<dyn {}>`",
-                    &snippet[5..]
-                ));
-            }
-            err.help("alternatively, create a new `enum` with a variant for each returned type");
-            let impl_trait_msg = "for information on `impl Trait`, see \
+            self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, return_sp);
+        }
+        err
+    }
+
+    fn add_impl_trait_explanation<'a>(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        fcx: &FnCtxt<'a, 'tcx>,
+        expected: Ty<'tcx>,
+        sp: Span,
+        return_sp: Span,
+    ) {
+        err.span_label(return_sp, "expected because this return type...");
+        err.span_label(
+            sp,
+            format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)),
+        );
+        let impl_trait_msg = "for information on `impl Trait`, see \
                 <https://doc.rust-lang.org/book/ch10-02-traits.html\
                 #returning-types-that-implement-traits>";
-            let trait_obj_msg = "for information on trait objects, see \
+        let trait_obj_msg = "for information on trait objects, see \
                 <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
                 #using-trait-objects-that-allow-for-values-of-different-types>";
-            err.note(impl_trait_msg);
-            if has_impl {
-                err.note(trait_obj_msg);
-            }
+        err.note("to return `impl Trait`, all returned values must be of the same type");
+        err.note(impl_trait_msg);
+        let snippet = fcx
+            .tcx
+            .sess
+            .source_map()
+            .span_to_snippet(return_sp)
+            .unwrap_or_else(|_| "dyn Trait".to_string());
+        let mut snippet_iter = snippet.split_whitespace();
+        let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
+        if has_impl {
+            err.help(&format!(
+                "you can instead return a trait object using `Box<dyn {}>`",
+                &snippet[5..]
+            ));
+            err.note(trait_obj_msg);
         }
-        err
+        err.help("alternatively, create a new `enum` with a variant for each returned type");
     }
 
     fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index 3d0707c091644..ac101f8f3ce36 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -82,11 +82,18 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bal() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = note: if trait `Trait` was object safe, you could return a trait object
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = note: if all the returned values were of the same type you could use `impl Trait` as the return type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = note: you can create a new `enum` with a variant for each returned type
+help: return a trait object instead
+   |
+LL | fn bal() -> Box<dyn Trait> {
+LL |     if true {
+LL |         return Box::new(Struct);
+LL |     }
+LL |     Box::new(42)
+   |
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index ceb32dd4cd33e..a399fadbc5db5 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -11,10 +11,10 @@ LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn Foo>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn Foo>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
index 87daab5ca7a22..9859c73b7b18b 100644
--- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -11,10 +11,10 @@ LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
@@ -29,10 +29,10 @@ LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
@@ -47,10 +47,10 @@ LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
@@ -77,10 +77,10 @@ LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
@@ -97,10 +97,10 @@ LL | |     }
    | |_____^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
@@ -115,10 +115,10 @@ LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
    |
    = note: to return `impl Trait`, all returned values must be of the same type
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
-   = help: alternatively, create a new `enum` with a variant for each returned type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
 
 error: aborting due to 7 previous errors
 

From 00e262689599a6a753bbf7ce8786e07ed100d238 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 15 Jan 2020 15:49:54 -0800
Subject: [PATCH 16/25] Account for object safety when suggesting `Box<dyn
 Trait>`

---
 .../traits/error_reporting/suggestions.rs     |  4 +-
 src/librustc_hir/hir.rs                       |  7 +++
 src/librustc_typeck/check/coercion.rs         | 53 +++++++++++++++----
 ...n-trait-return-should-be-impl-trait.stderr |  2 +-
 src/test/ui/impl-trait/equality.stderr        |  2 +-
 ...safe-trait-in-return-position-dyn-trait.rs | 35 ++++++++++++
 ...-trait-in-return-position-dyn-trait.stderr | 21 ++++++++
 ...afe-trait-in-return-position-impl-trait.rs | 46 ++++++++++++++++
 ...trait-in-return-position-impl-trait.stderr | 39 ++++++++++++++
 ...type-err-cause-on-impl-trait-return.stderr | 12 ++---
 10 files changed, 202 insertions(+), 19 deletions(-)
 create mode 100644 src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs
 create mode 100644 src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
 create mode 100644 src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs
 create mode 100644 src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr

diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index 7c1b1041c34c3..c3af063d518f0 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -696,11 +696,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
                 ));
                 err.multipart_suggestion(
-                        "return a trait object instead",
+                    "return a boxed trait object instead",
                     suggestions,
                     Applicability::MaybeIncorrect,
                 );
             } else {
+                // This is currently not possible to trigger because E0038 takes precedence, but
+                // leave it in for completeness in case anything changes in an earlier stage.
                 err.note(&format!(
                     "if trait `{}` was object safe, you could return a trait object",
                     trait_obj,
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 550e3654d0800..5c1d600c837c4 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -377,6 +377,13 @@ pub enum GenericBound<'hir> {
 }
 
 impl GenericBound<'_> {
+    pub fn trait_def_id(&self) -> Option<DefId> {
+        match self {
+            GenericBound::Trait(data, _) => Some(data.trait_ref.trait_def_id()),
+            _ => None,
+        }
+    }
+
     pub fn span(&self) -> Span {
         match self {
             &GenericBound::Trait(ref t, ..) => t.span,
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 768e532fa3b91..a32fbff7bfe2d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -55,6 +55,7 @@ use crate::check::{FnCtxt, Needs};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::infer::{Coercion, InferOk, InferResult};
 use rustc::session::parse::feature_err;
+use rustc::traits::object_safety_violations;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -68,8 +69,8 @@ use rustc_error_codes::*;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_span::{self, Span};
 use rustc_span::symbol::sym;
+use rustc_span::{self, Span};
 use rustc_target::spec::abi::Abi;
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
@@ -1311,7 +1312,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
 
         let mut pointing_at_return_type = false;
-        let mut return_sp = None;
+        let mut fn_output = None;
 
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
@@ -1348,11 +1349,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 );
             }
             if !pointing_at_return_type {
-                return_sp = Some(fn_decl.output.span()); // `impl Trait` return type
+                fn_output = Some(&fn_decl.output); // `impl Trait` return type
             }
         }
-        if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
-            self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, return_sp);
+        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
+            self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output);
         }
         err
     }
@@ -1363,8 +1364,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         fcx: &FnCtxt<'a, 'tcx>,
         expected: Ty<'tcx>,
         sp: Span,
-        return_sp: Span,
+        fn_output: &hir::FunctionRetTy<'_>,
     ) {
+        let return_sp = fn_output.span();
         err.span_label(return_sp, "expected because this return type...");
         err.span_label(
             sp,
@@ -1386,11 +1388,42 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             .unwrap_or_else(|_| "dyn Trait".to_string());
         let mut snippet_iter = snippet.split_whitespace();
         let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
+        // Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe.
+        let mut is_object_safe = false;
+        if let hir::FunctionRetTy::Return(ty) = fn_output {
+            // Get the return type.
+            if let hir::TyKind::Def(..) = ty.kind {
+                let ty = AstConv::ast_ty_to_ty(fcx, ty);
+                // Get the `impl Trait`'s `DefId`.
+                if let ty::Opaque(def_id, _) = ty.kind {
+                    let hir_id = fcx.tcx.hir().as_local_hir_id(def_id).unwrap();
+                    // Get the `impl Trait`'s `Item` so that we can get its trait bounds and
+                    // get the `Trait`'s `DefId`.
+                    if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
+                        fcx.tcx.hir().expect_item(hir_id).kind
+                    {
+                        // Are of this `impl Trait`'s traits object safe?
+                        is_object_safe = bounds.iter().all(|bound| {
+                            bound.trait_def_id().map_or(false, |def_id| {
+                                object_safety_violations(fcx.tcx, def_id).is_empty()
+                            })
+                        })
+                    }
+                }
+            }
+        };
         if has_impl {
-            err.help(&format!(
-                "you can instead return a trait object using `Box<dyn {}>`",
-                &snippet[5..]
-            ));
+            if is_object_safe {
+                err.help(&format!(
+                    "you can instead return a boxed trait object using `Box<dyn {}>`",
+                    &snippet[5..]
+                ));
+            } else {
+                err.help(&format!(
+                    "if the trait `{}` were object safe, you could return a boxed trait object",
+                    &snippet[5..]
+                ));
+            }
             err.note(trait_obj_msg);
         }
         err.help("alternatively, create a new `enum` with a variant for each returned type");
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index ac101f8f3ce36..977a7ef0e0244 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -86,7 +86,7 @@ LL | fn bal() -> dyn Trait {
    = note: if all the returned values were of the same type you could use `impl Trait` as the return type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
    = note: you can create a new `enum` with a variant for each returned type
-help: return a trait object instead
+help: return a boxed trait object instead
    |
 LL | fn bal() -> Box<dyn Trait> {
 LL |     if true {
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index a399fadbc5db5..9178358b60a9c 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -12,7 +12,7 @@ LL |     0_u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn Foo>`
+   = help: if the trait `Foo` were object safe, you could return a boxed trait object
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs
new file mode 100644
index 0000000000000..ab3086c78b3a1
--- /dev/null
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.rs
@@ -0,0 +1,35 @@
+#![allow(bare_trait_objects)]
+trait NotObjectSafe {
+    fn foo() -> Self;
+}
+
+struct A;
+struct B;
+
+impl NotObjectSafe for A {
+    fn foo() -> Self {
+        A
+    }
+}
+
+impl NotObjectSafe for B {
+    fn foo() -> Self {
+        B
+    }
+}
+
+fn car() -> dyn NotObjectSafe { //~ ERROR the trait `NotObjectSafe` cannot be made into an object
+    if true {
+        return A;
+    }
+    B
+}
+
+fn cat() -> Box<dyn NotObjectSafe> { //~ ERROR the trait `NotObjectSafe` cannot be made into an
+    if true {
+        return Box::new(A);
+    }
+    Box::new(B)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
new file mode 100644
index 0000000000000..0c8d267c13434
--- /dev/null
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
@@ -0,0 +1,21 @@
+error[E0038]: the trait `NotObjectSafe` cannot be made into an object
+  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:1
+   |
+LL |     fn foo() -> Self;
+   |        --- associated function `foo` has no `self` parameter
+...
+LL | fn car() -> dyn NotObjectSafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+
+error[E0038]: the trait `NotObjectSafe` cannot be made into an object
+  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:1
+   |
+LL |     fn foo() -> Self;
+   |        --- associated function `foo` has no `self` parameter
+...
+LL | fn cat() -> Box<dyn NotObjectSafe> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs
new file mode 100644
index 0000000000000..503515013b9ab
--- /dev/null
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.rs
@@ -0,0 +1,46 @@
+trait NotObjectSafe {
+    fn foo() -> Self;
+}
+
+trait ObjectSafe {
+    fn bar(&self);
+}
+
+struct A;
+struct B;
+
+impl NotObjectSafe for A {
+    fn foo() -> Self {
+        A
+    }
+}
+
+impl NotObjectSafe for B {
+    fn foo() -> Self {
+        B
+    }
+}
+
+impl ObjectSafe for A {
+    fn bar(&self) {}
+}
+
+impl ObjectSafe for B {
+    fn bar(&self) {}
+}
+
+fn can() -> impl NotObjectSafe {
+    if true {
+        return A;
+    }
+    B //~ ERROR mismatched types
+}
+
+fn cat() -> impl ObjectSafe {
+    if true {
+        return A;
+    }
+    B //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
new file mode 100644
index 0000000000000..dd4260fbe4f91
--- /dev/null
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
+   |
+LL | fn can() -> impl NotObjectSafe {
+   |             ------------------ expected because this return type...
+LL |     if true {
+LL |         return A;
+   |                - ...is found to be `A` here
+LL |     }
+LL |     B
+   |     ^ expected struct `A`, found struct `B`
+   |
+   = note: to return `impl Trait`, all returned values must be of the same type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
+
+error[E0308]: mismatched types
+  --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
+   |
+LL | fn cat() -> impl ObjectSafe {
+   |             --------------- expected because this return type...
+LL |     if true {
+LL |         return A;
+   |                - ...is found to be `A` here
+LL |     }
+LL |     B
+   |     ^ expected struct `A`, found struct `B`
+   |
+   = note: to return `impl Trait`, all returned values must be of the same type
+   = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+   = help: you can instead return a boxed trait object using `Box<dyn ObjectSafe>`
+   = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+   = help: alternatively, create a new `enum` with a variant for each returned type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
index 9859c73b7b18b..b663cccbeef0f 100644
--- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -12,7 +12,7 @@ LL |     1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
@@ -30,7 +30,7 @@ LL |         return 1u32;
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
@@ -48,7 +48,7 @@ LL |         1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
@@ -78,7 +78,7 @@ LL |         _ => 1u32,
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
@@ -98,7 +98,7 @@ LL | |     }
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 
@@ -116,7 +116,7 @@ LL |             1u32
    |
    = note: to return `impl Trait`, all returned values must be of the same type
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-   = help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
+   = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
    = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
    = help: alternatively, create a new `enum` with a variant for each returned type
 

From 3fd1af5fdb59a49e9eb5e05ff15fef6b8514ae31 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 3 Jan 2020 13:33:28 +0100
Subject: [PATCH 17/25] let rustfmt undo most of my edits :(

---
 src/librustc/mir/interpret/error.rs        |  3 +--
 src/librustc_mir/interpret/cast.rs         | 20 +++++++++-----------
 src/librustc_mir/interpret/eval_context.rs | 12 +++---------
 src/librustc_mir/interpret/memory.rs       |  3 +--
 src/librustc_mir/interpret/operand.rs      |  4 +---
 src/librustc_mir/interpret/validity.rs     |  6 ++----
 6 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 29b3b045ca5fe..42d896af8014d 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -137,8 +137,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
         let must_error = match self.error {
             InterpError::MachineStop(_) => bug!("CTFE does not stop"),
-            err_inval!(Layout(LayoutError::Unknown(_)))
-            | err_inval!(TooGeneric) => {
+            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
                 return Err(ErrorHandled::TooGeneric);
             }
             err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 6d0b6bf70ad8c..9461a06690212 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -118,17 +118,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
             // are represented as integers.
-            _ => {
-                assert!(
-                    src.layout.ty.is_bool()
-                        || src.layout.ty.is_char()
-                        || src.layout.ty.is_enum()
-                        || src.layout.ty.is_integral()
-                        || src.layout.ty.is_any_ptr(),
-                    "Unexpected cast from type {:?}",
-                    src.layout.ty
-                )
-            }
+            _ => assert!(
+                src.layout.ty.is_bool()
+                    || src.layout.ty.is_char()
+                    || src.layout.ty.is_enum()
+                    || src.layout.ty.is_integral()
+                    || src.layout.ty.is_any_ptr(),
+                "Unexpected cast from type {:?}",
+                src.layout.ty
+            ),
         }
 
         // Handle cast from a univariant (ZST) enum.
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 3d590fb820359..206d3d156735e 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -152,16 +152,10 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
         &mut self,
     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
         match self.value {
-            LocalValue::Dead => {
-                throw_unsup!(DeadLocal)
-            }
-            LocalValue::Live(Operand::Indirect(mplace)) => {
-                Ok(Err(mplace))
-            }
+            LocalValue::Dead => throw_unsup!(DeadLocal),
+            LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
             ref mut local @ LocalValue::Live(Operand::Immediate(_))
-            | ref mut local @ LocalValue::Uninitialized => {
-                Ok(Ok(local))
-            }
+            | ref mut local @ LocalValue::Uninitialized => Ok(Ok(local)),
         }
     }
 }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 3386254c93b75..0bcdf9ae3c1f2 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -580,8 +580,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
                 Ok((layout.size, layout.align.abi))
             }
-            Some(GlobalAlloc::Memory(alloc)) =>
-            {
+            Some(GlobalAlloc::Memory(alloc)) => {
                 // Need to duplicate the logic here, because the global allocations have
                 // different associated types than the interpreter-local ones.
                 Ok((alloc.size, alloc.align))
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 34a32daaab65f..d1c08da6cbee5 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -543,9 +543,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | ty::ConstKind::Placeholder(..) => {
                 bug!("eval_const_to_op: Unexpected ConstKind {:?}", val)
             }
-            ty::ConstKind::Value(val_val) => {
-                val_val
-            }
+            ty::ConstKind::Value(val_val) => val_val,
         };
         // Other cases need layout.
         let layout = from_known_layout(layout, || self.layout_of(val.ty))?;
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index d0fef08bb60c7..9f713dfd5e607 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -114,8 +114,7 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
             ClosureVar(name) => write!(out, ".<closure-var({})>", name),
             TupleElem(idx) => write!(out, ".{}", idx),
             ArrayElem(idx) => write!(out, "[{}]", idx),
-            Deref =>
-            {
+            Deref => {
                 // This does not match Rust syntax, but it is more readable for long paths -- and
                 // some of the other items here also are not Rust syntax.  Actually we can't
                 // even use the usual syntax because we are just showing the projections,
@@ -206,8 +205,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
             ty::Adt(def, ..) if def.is_enum() => {
                 // we might be projecting *to* a variant, or to a field *in*a variant.
                 match layout.variants {
-                    layout::Variants::Single { index } =>
-                    {
+                    layout::Variants::Single { index } => {
                         // Inside a variant
                         PathElem::Field(def.variants[index].fields[field].ident.name)
                     }

From c781d15da32bf82977311af6f056ee2fc3506bda Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 6 Jan 2020 11:35:55 +0100
Subject: [PATCH 18/25] adjust Deref comment

---
 src/librustc_mir/interpret/validity.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 9f713dfd5e607..ec9ac52a87c3a 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -114,13 +114,11 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
             ClosureVar(name) => write!(out, ".<closure-var({})>", name),
             TupleElem(idx) => write!(out, ".{}", idx),
             ArrayElem(idx) => write!(out, "[{}]", idx),
-            Deref => {
-                // This does not match Rust syntax, but it is more readable for long paths -- and
-                // some of the other items here also are not Rust syntax.  Actually we can't
-                // even use the usual syntax because we are just showing the projections,
-                // not the root.
-                write!(out, ".<deref>")
-            }
+            // `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and
+            // some of the other items here also are not Rust syntax.  Actually we can't
+            // even use the usual syntax because we are just showing the projections,
+            // not the root.
+            Deref => write!(out, ".<deref>"),
             Tag => write!(out, ".<enum-tag>"),
             DynDowncast => write!(out, ".<dyn-downcast>"),
         }

From 0f70daa9b06882d7fb684a60160e4949d2861136 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 12 Jan 2020 13:29:00 +0300
Subject: [PATCH 19/25] resolve: Move privacy error reporting into a separate
 method

Give named fields to `struct PrivacyError`
Move `fn report_ambiguity_error` to `diagnostics.rs`
---
 src/librustc_resolve/diagnostics.rs | 153 +++++++++++++++++++++++++-
 src/librustc_resolve/imports.rs     |   6 +-
 src/librustc_resolve/lib.rs         | 162 ++--------------------------
 3 files changed, 166 insertions(+), 155 deletions(-)

diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 9742067975499..f83daa1636752 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
@@ -20,8 +20,9 @@ use syntax::util::lev_distance::find_best_match_for_name;
 
 use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
 use crate::path_names_to_string;
-use crate::VisResolutionError;
+use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
 use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
+use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};
 
 use rustc_error_codes::*;
@@ -802,6 +803,154 @@ impl<'a> Resolver<'a> {
         }
         false
     }
+
+    fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
+        let res = b.res();
+        if b.span.is_dummy() {
+            let add_built_in = match b.res() {
+                // These already contain the "built-in" prefix or look bad with it.
+                Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false,
+                _ => true,
+            };
+            let (built_in, from) = if from_prelude {
+                ("", " from prelude")
+            } else if b.is_extern_crate()
+                && !b.is_import()
+                && self.session.opts.externs.get(&ident.as_str()).is_some()
+            {
+                ("", " passed with `--extern`")
+            } else if add_built_in {
+                (" built-in", "")
+            } else {
+                ("", "")
+            };
+
+            let article = if built_in.is_empty() { res.article() } else { "a" };
+            format!(
+                "{a}{built_in} {thing}{from}",
+                a = article,
+                thing = res.descr(),
+                built_in = built_in,
+                from = from
+            )
+        } else {
+            let introduced = if b.is_import() { "imported" } else { "defined" };
+            format!("the {thing} {introduced} here", thing = res.descr(), introduced = introduced)
+        }
+    }
+
+    crate fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
+        let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
+        let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
+            // We have to print the span-less alternative first, otherwise formatting looks bad.
+            (b2, b1, misc2, misc1, true)
+        } else {
+            (b1, b2, misc1, misc2, false)
+        };
+
+        let mut err = struct_span_err!(
+            self.session,
+            ident.span,
+            E0659,
+            "`{ident}` is ambiguous ({why})",
+            ident = ident,
+            why = kind.descr()
+        );
+        err.span_label(ident.span, "ambiguous name");
+
+        let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
+            let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
+            let note_msg = format!(
+                "`{ident}` could{also} refer to {what}",
+                ident = ident,
+                also = also,
+                what = what
+            );
+
+            let thing = b.res().descr();
+            let mut help_msgs = Vec::new();
+            if b.is_glob_import()
+                && (kind == AmbiguityKind::GlobVsGlob
+                    || kind == AmbiguityKind::GlobVsExpanded
+                    || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
+            {
+                help_msgs.push(format!(
+                    "consider adding an explicit import of \
+                     `{ident}` to disambiguate",
+                    ident = ident
+                ))
+            }
+            if b.is_extern_crate() && ident.span.rust_2018() {
+                help_msgs.push(format!(
+                    "use `::{ident}` to refer to this {thing} unambiguously",
+                    ident = ident,
+                    thing = thing,
+                ))
+            }
+            if misc == AmbiguityErrorMisc::SuggestCrate {
+                help_msgs.push(format!(
+                    "use `crate::{ident}` to refer to this {thing} unambiguously",
+                    ident = ident,
+                    thing = thing,
+                ))
+            } else if misc == AmbiguityErrorMisc::SuggestSelf {
+                help_msgs.push(format!(
+                    "use `self::{ident}` to refer to this {thing} unambiguously",
+                    ident = ident,
+                    thing = thing,
+                ))
+            }
+
+            err.span_note(b.span, &note_msg);
+            for (i, help_msg) in help_msgs.iter().enumerate() {
+                let or = if i == 0 { "" } else { "or " };
+                err.help(&format!("{}{}", or, help_msg));
+            }
+        };
+
+        could_refer_to(b1, misc1, "");
+        could_refer_to(b2, misc2, " also");
+        err.emit();
+    }
+
+    crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
+        let PrivacyError { ident, binding, .. } = *privacy_error;
+        let session = &self.session;
+        let mk_struct_span_error = |is_constructor| {
+            struct_span_err!(
+                session,
+                ident.span,
+                E0603,
+                "{}{} `{}` is private",
+                binding.res().descr(),
+                if is_constructor { " constructor" } else { "" },
+                ident.name,
+            )
+        };
+
+        let mut err = if let NameBindingKind::Res(
+            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
+            _,
+        ) = binding.kind
+        {
+            let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
+            if let Some(fields) = self.field_names.get(&def_id) {
+                let mut err = mk_struct_span_error(true);
+                let first_field = fields.first().expect("empty field list in the map");
+                err.span_label(
+                    fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)),
+                    "a constructor is private if any of the fields is private",
+                );
+                err
+            } else {
+                mk_struct_span_error(false)
+            }
+        } else {
+            mk_struct_span_error(false)
+        };
+
+        err.emit();
+    }
 }
 
 impl<'a, 'b> ImportResolver<'a, 'b> {
diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs
index 5bd10303162b2..9f459834175c1 100644
--- a/src/librustc_resolve/imports.rs
+++ b/src/librustc_resolve/imports.rs
@@ -319,7 +319,11 @@ impl<'a> Resolver<'a> {
                        // Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
                        !(self.last_import_segment && binding.is_extern_crate())
                         {
-                            self.privacy_errors.push(PrivacyError(path_span, ident, binding));
+                            self.privacy_errors.push(PrivacyError {
+                                ident,
+                                binding,
+                                dedup_span: path_span,
+                            });
                         }
 
                         Ok(binding)
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 8d5afb194a175..60a0049f5da37 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2,12 +2,9 @@
 //!
 //! Module structure of the crate is built here.
 //! Paths in macros, imports, expressions, types, patterns are resolved here.
-//! Label names are resolved here as well.
+//! Label and lifetime names are resolved here as well.
 //!
 //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`.
-//! Lifetime names are resolved in `librustc/middle/resolve_lifetime.rs`.
-
-// ignore-tidy-filelength
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(bool_to_option)]
@@ -33,7 +30,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def::Namespace::*;
-use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
+use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
 use rustc_hir::{GlobMap, TraitMap};
@@ -604,7 +601,11 @@ impl<'a> NameBindingKind<'a> {
     }
 }
 
-struct PrivacyError<'a>(Span, Ident, &'a NameBinding<'a>);
+struct PrivacyError<'a> {
+    ident: Ident,
+    binding: &'a NameBinding<'a>,
+    dedup_span: Span,
+}
 
 struct UseError<'a> {
     err: DiagnosticBuilder<'a>,
@@ -2446,115 +2447,6 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
-        let res = b.res();
-        if b.span.is_dummy() {
-            let add_built_in = match b.res() {
-                // These already contain the "built-in" prefix or look bad with it.
-                Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false,
-                _ => true,
-            };
-            let (built_in, from) = if from_prelude {
-                ("", " from prelude")
-            } else if b.is_extern_crate()
-                && !b.is_import()
-                && self.session.opts.externs.get(&ident.as_str()).is_some()
-            {
-                ("", " passed with `--extern`")
-            } else if add_built_in {
-                (" built-in", "")
-            } else {
-                ("", "")
-            };
-
-            let article = if built_in.is_empty() { res.article() } else { "a" };
-            format!(
-                "{a}{built_in} {thing}{from}",
-                a = article,
-                thing = res.descr(),
-                built_in = built_in,
-                from = from
-            )
-        } else {
-            let introduced = if b.is_import() { "imported" } else { "defined" };
-            format!("the {thing} {introduced} here", thing = res.descr(), introduced = introduced)
-        }
-    }
-
-    fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
-        let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
-        let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
-            // We have to print the span-less alternative first, otherwise formatting looks bad.
-            (b2, b1, misc2, misc1, true)
-        } else {
-            (b1, b2, misc1, misc2, false)
-        };
-
-        let mut err = struct_span_err!(
-            self.session,
-            ident.span,
-            E0659,
-            "`{ident}` is ambiguous ({why})",
-            ident = ident,
-            why = kind.descr()
-        );
-        err.span_label(ident.span, "ambiguous name");
-
-        let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
-            let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
-            let note_msg = format!(
-                "`{ident}` could{also} refer to {what}",
-                ident = ident,
-                also = also,
-                what = what
-            );
-
-            let thing = b.res().descr();
-            let mut help_msgs = Vec::new();
-            if b.is_glob_import()
-                && (kind == AmbiguityKind::GlobVsGlob
-                    || kind == AmbiguityKind::GlobVsExpanded
-                    || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
-            {
-                help_msgs.push(format!(
-                    "consider adding an explicit import of \
-                     `{ident}` to disambiguate",
-                    ident = ident
-                ))
-            }
-            if b.is_extern_crate() && ident.span.rust_2018() {
-                help_msgs.push(format!(
-                    "use `::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
-            }
-            if misc == AmbiguityErrorMisc::SuggestCrate {
-                help_msgs.push(format!(
-                    "use `crate::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
-            } else if misc == AmbiguityErrorMisc::SuggestSelf {
-                help_msgs.push(format!(
-                    "use `self::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
-            }
-
-            err.span_note(b.span, &note_msg);
-            for (i, help_msg) in help_msgs.iter().enumerate() {
-                let or = if i == 0 { "" } else { "or " };
-                err.help(&format!("{}{}", or, help_msg));
-            }
-        };
-
-        could_refer_to(b1, misc1, "");
-        could_refer_to(b2, misc2, " also");
-        err.emit();
-    }
-
     fn report_errors(&mut self, krate: &Crate) {
         self.report_with_use_injections(krate);
 
@@ -2575,43 +2467,9 @@ impl<'a> Resolver<'a> {
         }
 
         let mut reported_spans = FxHashSet::default();
-        for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
-            if reported_spans.insert(dedup_span) {
-                let session = &self.session;
-                let mk_struct_span_error = |is_constructor| {
-                    struct_span_err!(
-                        session,
-                        ident.span,
-                        E0603,
-                        "{}{} `{}` is private",
-                        binding.res().descr(),
-                        if is_constructor { " constructor" } else { "" },
-                        ident.name,
-                    )
-                };
-
-                let mut err = if let NameBindingKind::Res(
-                    Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
-                    _,
-                ) = binding.kind
-                {
-                    let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
-                    if let Some(fields) = self.field_names.get(&def_id) {
-                        let mut err = mk_struct_span_error(true);
-                        let first_field = fields.first().expect("empty field list in the map");
-                        err.span_label(
-                            fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)),
-                            "a constructor is private if any of the fields is private",
-                        );
-                        err
-                    } else {
-                        mk_struct_span_error(false)
-                    }
-                } else {
-                    mk_struct_span_error(false)
-                };
-
-                err.emit();
+        for error in &self.privacy_errors {
+            if reported_spans.insert(error.dedup_span) {
+                self.report_privacy_error(error);
             }
         }
     }

From 28c3f6eb409596be9c0c0a59dc1c26e216d9e57a Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 12 Jan 2020 16:04:03 +0300
Subject: [PATCH 20/25] resolve: Point at the private item definitions in
 privacy errors

---
 src/librustc_resolve/diagnostics.rs           |  24 +-
 src/test/ui/error-codes/E0603.stderr          |   8 +-
 src/test/ui/error-festival.stderr             |   8 +-
 src/test/ui/export-import.stderr              |   8 +-
 src/test/ui/export-tag-variant.stderr         |   8 +-
 src/test/ui/export.stderr                     |   8 +-
 .../ui/extern/extern-crate-visibility.stderr  |  16 +-
 src/test/ui/hygiene/privacy.stderr            |   8 +-
 src/test/ui/import.stderr                     |   8 +-
 src/test/ui/imports/issue-55884-2.stderr      |   8 +-
 src/test/ui/imports/reexports.stderr          |  16 +-
 .../ui/imports/unresolved-imports-used.stderr |   8 +-
 src/test/ui/issues/issue-10545.stderr         |   8 +-
 src/test/ui/issues/issue-11593.stderr         |   8 +-
 src/test/ui/issues/issue-11680.stderr         |  16 +-
 src/test/ui/issues/issue-13407.stderr         |   8 +-
 src/test/ui/issues/issue-13641.stderr         |  16 +-
 src/test/ui/issues/issue-16725.stderr         |   8 +-
 .../issues/issue-17718-const-privacy.stderr   |  16 +-
 src/test/ui/issues/issue-28388-2.stderr       |   8 +-
 src/test/ui/issues/issue-29161.stderr         |   8 +-
 src/test/ui/issues/issue-38857.stderr         |   8 +-
 src/test/ui/issues/issue-3993.stderr          |   8 +-
 .../macros/macro-local-data-key-priv.stderr   |   9 +-
 .../ui/parser/macro/pub-item-macro.stderr     |  11 +-
 src/test/ui/privacy/decl-macro.stderr         |   8 +-
 src/test/ui/privacy/privacy-in-paths.stderr   |  24 +-
 src/test/ui/privacy/privacy-ns2.stderr        |  24 +-
 src/test/ui/privacy/privacy-ufcs.stderr       |   8 +-
 src/test/ui/privacy/privacy1.stderr           | 104 ++++-
 src/test/ui/privacy/privacy2.stderr           |   8 +-
 src/test/ui/privacy/privacy4.stderr           |   8 +-
 src/test/ui/privacy/privacy5.stderr           | 384 +++++++++++++++---
 .../ui/privacy/private-item-simple.stderr     |   8 +-
 src/test/ui/privacy/restricted/test.stderr    |  16 +-
 .../proc-macro/disappearing-resolution.stderr |   8 +-
 .../ui/reachable/unreachable-variant.stderr   |   8 +-
 src/test/ui/resolve/privacy-enum-ctor.stderr  |  32 +-
 .../ui/resolve/privacy-struct-ctor.stderr     |  48 ++-
 .../ui/rfc-2008-non-exhaustive/struct.stderr  |  16 +-
 .../ui/rfc-2008-non-exhaustive/variant.stderr |  40 +-
 .../shadowed/shadowed-use-visibility.stderr   |  16 +-
 .../ui/stability-in-private-module.stderr     |   8 +-
 .../ui/static/static-priv-by-default2.stderr  |  16 +-
 .../structs/struct-variant-privacy-xc.stderr  |  16 +-
 .../ui/structs/struct-variant-privacy.stderr  |  16 +-
 src/test/ui/use/use-from-trait-xc.stderr      |  16 +-
 src/test/ui/use/use-mod/use-mod-3.stderr      |  16 +-
 .../xcrate/xcrate-private-by-default.stderr   |  80 +++-
 49 files changed, 1034 insertions(+), 154 deletions(-)

diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index f83daa1636752..20c8f78b1cf0e 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -917,15 +917,21 @@ impl<'a> Resolver<'a> {
         let PrivacyError { ident, binding, .. } = *privacy_error;
         let session = &self.session;
         let mk_struct_span_error = |is_constructor| {
-            struct_span_err!(
-                session,
-                ident.span,
-                E0603,
-                "{}{} `{}` is private",
-                binding.res().descr(),
-                if is_constructor { " constructor" } else { "" },
-                ident.name,
-            )
+            let mut descr = binding.res().descr().to_string();
+            if is_constructor {
+                descr += " constructor";
+            }
+
+            let mut err =
+                struct_span_err!(session, ident.span, E0603, "{} `{}` is private", descr, ident);
+
+            err.span_label(ident.span, &format!("this {} is private", descr));
+            err.span_note(
+                session.source_map().def_span(binding.span),
+                &format!("the {} `{}` is defined here", descr, ident),
+            );
+
+            err
         };
 
         let mut err = if let NameBindingKind::Res(
diff --git a/src/test/ui/error-codes/E0603.stderr b/src/test/ui/error-codes/E0603.stderr
index 444005e086f1b..724d04954a3c7 100644
--- a/src/test/ui/error-codes/E0603.stderr
+++ b/src/test/ui/error-codes/E0603.stderr
@@ -2,7 +2,13 @@ error[E0603]: constant `PRIVATE` is private
   --> $DIR/E0603.rs:6:17
    |
 LL |     SomeModule::PRIVATE;
-   |                 ^^^^^^^
+   |                 ^^^^^^^ this constant is private
+   |
+note: the constant `PRIVATE` is defined here
+  --> $DIR/E0603.rs:2:5
+   |
+LL |     const PRIVATE: u32 = 0x_a_bad_1dea_u32;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 6b80d99b3afe9..9b69b3733642b 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -8,7 +8,13 @@ error[E0603]: constant `FOO` is private
   --> $DIR/error-festival.rs:22:10
    |
 LL |     foo::FOO;
-   |          ^^^
+   |          ^^^ this constant is private
+   |
+note: the constant `FOO` is defined here
+  --> $DIR/error-festival.rs:7:5
+   |
+LL |     const FOO: u32 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^
 
 error[E0368]: binary assignment operation `+=` cannot be applied to type `&str`
   --> $DIR/error-festival.rs:12:5
diff --git a/src/test/ui/export-import.stderr b/src/test/ui/export-import.stderr
index e02952e0fe092..8160775ab589e 100644
--- a/src/test/ui/export-import.stderr
+++ b/src/test/ui/export-import.stderr
@@ -2,7 +2,13 @@ error[E0603]: function `unexported` is private
   --> $DIR/export-import.rs:1:8
    |
 LL | use m::unexported;
-   |        ^^^^^^^^^^
+   |        ^^^^^^^^^^ this function is private
+   |
+note: the function `unexported` is defined here
+  --> $DIR/export-import.rs:7:5
+   |
+LL |     fn unexported() { }
+   |     ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/export-tag-variant.stderr b/src/test/ui/export-tag-variant.stderr
index b5a2c12c436d0..f4537a2fb6fae 100644
--- a/src/test/ui/export-tag-variant.stderr
+++ b/src/test/ui/export-tag-variant.stderr
@@ -2,7 +2,13 @@ error[E0603]: enum `Y` is private
   --> $DIR/export-tag-variant.rs:7:26
    |
 LL | fn main() { let z = foo::Y::Y1; }
-   |                          ^
+   |                          ^ this enum is private
+   |
+note: the enum `Y` is defined here
+  --> $DIR/export-tag-variant.rs:4:5
+   |
+LL |     enum Y { Y1 }
+   |     ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/export.stderr b/src/test/ui/export.stderr
index a3668a502cdd4..107f531c09a3a 100644
--- a/src/test/ui/export.stderr
+++ b/src/test/ui/export.stderr
@@ -26,7 +26,13 @@ error[E0603]: function `z` is private
   --> $DIR/export.rs:10:18
    |
 LL | fn main() { foo::z(10); }
-   |                  ^
+   |                  ^ this function is private
+   |
+note: the function `z` is defined here
+  --> $DIR/export.rs:5:5
+   |
+LL |     fn z(y: isize) { log(debug, y); }
+   |     ^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/extern/extern-crate-visibility.stderr b/src/test/ui/extern/extern-crate-visibility.stderr
index 38c791ab83237..6d38b4d8d66d6 100644
--- a/src/test/ui/extern/extern-crate-visibility.stderr
+++ b/src/test/ui/extern/extern-crate-visibility.stderr
@@ -2,13 +2,25 @@ error[E0603]: crate `core` is private
   --> $DIR/extern-crate-visibility.rs:6:10
    |
 LL | use foo::core::cell;
-   |          ^^^^
+   |          ^^^^ this crate is private
+   |
+note: the crate `core` is defined here
+  --> $DIR/extern-crate-visibility.rs:2:5
+   |
+LL |     extern crate core;
+   |     ^^^^^^^^^^^^^^^^^^
 
 error[E0603]: crate `core` is private
   --> $DIR/extern-crate-visibility.rs:9:10
    |
 LL |     foo::core::cell::Cell::new(0);
-   |          ^^^^
+   |          ^^^^ this crate is private
+   |
+note: the crate `core` is defined here
+  --> $DIR/extern-crate-visibility.rs:2:5
+   |
+LL |     extern crate core;
+   |     ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/hygiene/privacy.stderr b/src/test/ui/hygiene/privacy.stderr
index 80fb4dd0f314a..0649dc0ec5836 100644
--- a/src/test/ui/hygiene/privacy.stderr
+++ b/src/test/ui/hygiene/privacy.stderr
@@ -2,7 +2,13 @@ error[E0603]: function `f` is private
   --> $DIR/privacy.rs:16:14
    |
 LL |         foo::f()
-   |              ^
+   |              ^ this function is private
+   |
+note: the function `f` is defined here
+  --> $DIR/privacy.rs:4:5
+   |
+LL |     fn f() {}
+   |     ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/import.stderr b/src/test/ui/import.stderr
index 6b320b198a0b1..c66a4fa7151dc 100644
--- a/src/test/ui/import.stderr
+++ b/src/test/ui/import.stderr
@@ -17,7 +17,13 @@ error[E0603]: unresolved item `foo` is private
   --> $DIR/import.rs:15:10
    |
 LL |     zed::foo();
-   |          ^^^
+   |          ^^^ this unresolved item is private
+   |
+note: the unresolved item `foo` is defined here
+  --> $DIR/import.rs:10:9
+   |
+LL |     use foo;
+   |         ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr
index d3b43783ee9c8..9e77283cd5946 100644
--- a/src/test/ui/imports/issue-55884-2.stderr
+++ b/src/test/ui/imports/issue-55884-2.stderr
@@ -2,7 +2,13 @@ error[E0603]: struct `ParseOptions` is private
   --> $DIR/issue-55884-2.rs:12:17
    |
 LL | pub use parser::ParseOptions;
-   |                 ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^ this struct is private
+   |
+note: the struct `ParseOptions` is defined here
+  --> $DIR/issue-55884-2.rs:9:9
+   |
+LL |     use ParseOptions;
+   |         ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/imports/reexports.stderr b/src/test/ui/imports/reexports.stderr
index 4388e2c276b8e..67c12e0c8d3ca 100644
--- a/src/test/ui/imports/reexports.stderr
+++ b/src/test/ui/imports/reexports.stderr
@@ -14,13 +14,25 @@ error[E0603]: module `foo` is private
   --> $DIR/reexports.rs:33:15
    |
 LL |     use b::a::foo::S;
-   |               ^^^
+   |               ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/reexports.rs:21:17
+   |
+LL |         pub use super::foo; // This is OK since the value `foo` is visible enough.
+   |                 ^^^^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/reexports.rs:34:15
    |
 LL |     use b::b::foo::S as T;
-   |               ^^^
+   |               ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/reexports.rs:26:17
+   |
+LL |         pub use super::*; // This is also OK since the value `foo` is visible enough.
+   |                 ^^^^^^^^
 
 warning: glob import doesn't reexport anything because no candidate is public enough
   --> $DIR/reexports.rs:9:17
diff --git a/src/test/ui/imports/unresolved-imports-used.stderr b/src/test/ui/imports/unresolved-imports-used.stderr
index b341e8e059288..d7280d2583a76 100644
--- a/src/test/ui/imports/unresolved-imports-used.stderr
+++ b/src/test/ui/imports/unresolved-imports-used.stderr
@@ -38,7 +38,13 @@ error[E0603]: function `quz` is private
   --> $DIR/unresolved-imports-used.rs:9:10
    |
 LL | use qux::quz;
-   |          ^^^
+   |          ^^^ this function is private
+   |
+note: the function `quz` is defined here
+  --> $DIR/unresolved-imports-used.rs:5:4
+   |
+LL |    fn quz() {}
+   |    ^^^^^^^^
 
 error: unused import: `qux::quy`
   --> $DIR/unresolved-imports-used.rs:16:5
diff --git a/src/test/ui/issues/issue-10545.stderr b/src/test/ui/issues/issue-10545.stderr
index 59d4fedcd2b40..4ed7028c0a06b 100644
--- a/src/test/ui/issues/issue-10545.stderr
+++ b/src/test/ui/issues/issue-10545.stderr
@@ -2,7 +2,13 @@ error[E0603]: struct `S` is private
   --> $DIR/issue-10545.rs:6:14
    |
 LL | fn foo(_: a::S) {
-   |              ^
+   |              ^ this struct is private
+   |
+note: the struct `S` is defined here
+  --> $DIR/issue-10545.rs:2:5
+   |
+LL |     struct S;
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-11593.stderr b/src/test/ui/issues/issue-11593.stderr
index c3e4412b042d7..bfb4d31323b13 100644
--- a/src/test/ui/issues/issue-11593.stderr
+++ b/src/test/ui/issues/issue-11593.stderr
@@ -2,7 +2,13 @@ error[E0603]: trait `Foo` is private
   --> $DIR/issue-11593.rs:7:24
    |
 LL | impl private_trait_xc::Foo for Bar {}
-   |                        ^^^
+   |                        ^^^ this trait is private
+   |
+note: the trait `Foo` is defined here
+  --> $DIR/auxiliary/private-trait-xc.rs:1:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-11680.stderr b/src/test/ui/issues/issue-11680.stderr
index 35cb2476992ac..898ac10f7d9a9 100644
--- a/src/test/ui/issues/issue-11680.stderr
+++ b/src/test/ui/issues/issue-11680.stderr
@@ -2,13 +2,25 @@ error[E0603]: enum `Foo` is private
   --> $DIR/issue-11680.rs:6:21
    |
 LL |     let _b = other::Foo::Bar(1);
-   |                     ^^^
+   |                     ^^^ this enum is private
+   |
+note: the enum `Foo` is defined here
+  --> $DIR/auxiliary/issue-11680.rs:1:1
+   |
+LL | enum Foo {
+   | ^^^^^^^^
 
 error[E0603]: enum `Foo` is private
   --> $DIR/issue-11680.rs:9:27
    |
 LL |     let _b = other::test::Foo::Bar(1);
-   |                           ^^^
+   |                           ^^^ this enum is private
+   |
+note: the enum `Foo` is defined here
+  --> $DIR/auxiliary/issue-11680.rs:6:5
+   |
+LL |     enum Foo {
+   |     ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr
index b280de3158fed..f211d623ab12b 100644
--- a/src/test/ui/issues/issue-13407.stderr
+++ b/src/test/ui/issues/issue-13407.stderr
@@ -2,7 +2,13 @@ error[E0603]: unit struct `C` is private
   --> $DIR/issue-13407.rs:6:8
    |
 LL |     A::C = 1;
-   |        ^
+   |        ^ this unit struct is private
+   |
+note: the unit struct `C` is defined here
+  --> $DIR/issue-13407.rs:2:5
+   |
+LL |     struct C;
+   |     ^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-13407.rs:6:12
diff --git a/src/test/ui/issues/issue-13641.stderr b/src/test/ui/issues/issue-13641.stderr
index 8e5001e3b694d..f90cb18b6fc9d 100644
--- a/src/test/ui/issues/issue-13641.stderr
+++ b/src/test/ui/issues/issue-13641.stderr
@@ -2,13 +2,25 @@ error[E0603]: struct `Foo` is private
   --> $DIR/issue-13641.rs:9:8
    |
 LL |     a::Foo::new();
-   |        ^^^
+   |        ^^^ this struct is private
+   |
+note: the struct `Foo` is defined here
+  --> $DIR/issue-13641.rs:2:5
+   |
+LL |     struct Foo;
+   |     ^^^^^^^^^^^
 
 error[E0603]: enum `Bar` is private
   --> $DIR/issue-13641.rs:11:8
    |
 LL |     a::Bar::new();
-   |        ^^^
+   |        ^^^ this enum is private
+   |
+note: the enum `Bar` is defined here
+  --> $DIR/issue-13641.rs:4:5
+   |
+LL |     enum Bar {}
+   |     ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-16725.stderr b/src/test/ui/issues/issue-16725.stderr
index 562ad940423c2..e0a1ca8a5ac31 100644
--- a/src/test/ui/issues/issue-16725.stderr
+++ b/src/test/ui/issues/issue-16725.stderr
@@ -2,7 +2,13 @@ error[E0603]: function `bar` is private
   --> $DIR/issue-16725.rs:6:19
    |
 LL |     unsafe { foo::bar(); }
-   |                   ^^^
+   |                   ^^^ this function is private
+   |
+note: the function `bar` is defined here
+  --> $DIR/auxiliary/issue-16725.rs:2:5
+   |
+LL |     fn bar();
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17718-const-privacy.stderr b/src/test/ui/issues/issue-17718-const-privacy.stderr
index 0b0de8a52590b..07d825ba9cb3b 100644
--- a/src/test/ui/issues/issue-17718-const-privacy.stderr
+++ b/src/test/ui/issues/issue-17718-const-privacy.stderr
@@ -2,13 +2,25 @@ error[E0603]: constant `B` is private
   --> $DIR/issue-17718-const-privacy.rs:5:8
    |
 LL | use a::B;
-   |        ^
+   |        ^ this constant is private
+   |
+note: the constant `B` is defined here
+  --> $DIR/issue-17718-const-privacy.rs:13:5
+   |
+LL |     const B: usize = 3;
+   |     ^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: constant `BAR` is private
   --> $DIR/issue-17718-const-privacy.rs:8:5
    |
 LL |     BAR,
-   |     ^^^
+   |     ^^^ this constant is private
+   |
+note: the constant `BAR` is defined here
+  --> $DIR/auxiliary/issue-17718-const-privacy.rs:4:1
+   |
+LL | const BAR: usize = 3;
+   | ^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-28388-2.stderr b/src/test/ui/issues/issue-28388-2.stderr
index 7bbe0bc5ff154..58bd775f295fc 100644
--- a/src/test/ui/issues/issue-28388-2.stderr
+++ b/src/test/ui/issues/issue-28388-2.stderr
@@ -2,7 +2,13 @@ error[E0603]: module `n` is private
   --> $DIR/issue-28388-2.rs:7:8
    |
 LL | use m::n::{};
-   |        ^
+   |        ^ this module is private
+   |
+note: the module `n` is defined here
+  --> $DIR/issue-28388-2.rs:4:5
+   |
+LL |     mod n {}
+   |     ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-29161.stderr b/src/test/ui/issues/issue-29161.stderr
index d30fd28a4a351..1bfa211ef7962 100644
--- a/src/test/ui/issues/issue-29161.stderr
+++ b/src/test/ui/issues/issue-29161.stderr
@@ -8,7 +8,13 @@ error[E0603]: struct `A` is private
   --> $DIR/issue-29161.rs:13:8
    |
 LL |     a::A::default();
-   |        ^
+   |        ^ this struct is private
+   |
+note: the struct `A` is defined here
+  --> $DIR/issue-29161.rs:2:5
+   |
+LL |     struct A;
+   |     ^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-38857.stderr b/src/test/ui/issues/issue-38857.stderr
index 5762e3d6ac00a..dd7970e014fdb 100644
--- a/src/test/ui/issues/issue-38857.stderr
+++ b/src/test/ui/issues/issue-38857.stderr
@@ -8,7 +8,13 @@ error[E0603]: module `sys` is private
   --> $DIR/issue-38857.rs:2:18
    |
 LL |     let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() };
-   |                  ^^^
+   |                  ^^^ this module is private
+   |
+note: the module `sys` is defined here
+  --> $SRC_DIR/libstd/lib.rs:LL:COL
+   |
+LL | mod sys;
+   | ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-3993.stderr b/src/test/ui/issues/issue-3993.stderr
index ce594a3f9bb27..3fa8ed4af28fa 100644
--- a/src/test/ui/issues/issue-3993.stderr
+++ b/src/test/ui/issues/issue-3993.stderr
@@ -2,7 +2,13 @@ error[E0603]: function `fly` is private
   --> $DIR/issue-3993.rs:1:10
    |
 LL | use zoo::fly;
-   |          ^^^
+   |          ^^^ this function is private
+   |
+note: the function `fly` is defined here
+  --> $DIR/issue-3993.rs:4:5
+   |
+LL |     fn fly() {}
+   |     ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/macro-local-data-key-priv.stderr b/src/test/ui/macros/macro-local-data-key-priv.stderr
index 9b44421808e88..72994d1652cd0 100644
--- a/src/test/ui/macros/macro-local-data-key-priv.stderr
+++ b/src/test/ui/macros/macro-local-data-key-priv.stderr
@@ -2,7 +2,14 @@ error[E0603]: constant `baz` is private
   --> $DIR/macro-local-data-key-priv.rs:8:10
    |
 LL |     bar::baz.with(|_| ());
-   |          ^^^
+   |          ^^^ this constant is private
+   |
+note: the constant `baz` is defined here
+  --> $DIR/macro-local-data-key-priv.rs:4:5
+   |
+LL |     thread_local!(static baz: f64 = 0.0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/macro/pub-item-macro.stderr b/src/test/ui/parser/macro/pub-item-macro.stderr
index fa25161ab50b2..ae981ac4cbee3 100644
--- a/src/test/ui/parser/macro/pub-item-macro.stderr
+++ b/src/test/ui/parser/macro/pub-item-macro.stderr
@@ -13,7 +13,16 @@ error[E0603]: static `x` is private
   --> $DIR/pub-item-macro.rs:17:23
    |
 LL |     let y: u32 = foo::x;
-   |                       ^
+   |                       ^ this static is private
+   |
+note: the static `x` is defined here
+  --> $DIR/pub-item-macro.rs:4:5
+   |
+LL |     static x: u32 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+...
+LL |     pub_x!();
+   |     --------- in this macro invocation
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/privacy/decl-macro.stderr b/src/test/ui/privacy/decl-macro.stderr
index 230cf95de6206..ae2e1b4b644a3 100644
--- a/src/test/ui/privacy/decl-macro.stderr
+++ b/src/test/ui/privacy/decl-macro.stderr
@@ -2,7 +2,13 @@ error[E0603]: macro `mac` is private
   --> $DIR/decl-macro.rs:8:8
    |
 LL |     m::mac!();
-   |        ^^^
+   |        ^^^ this macro is private
+   |
+note: the macro `mac` is defined here
+  --> $DIR/decl-macro.rs:4:5
+   |
+LL |     macro mac() {}
+   |     ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/privacy/privacy-in-paths.stderr b/src/test/ui/privacy/privacy-in-paths.stderr
index 4b9faca045709..8860d8f15f748 100644
--- a/src/test/ui/privacy/privacy-in-paths.stderr
+++ b/src/test/ui/privacy/privacy-in-paths.stderr
@@ -2,19 +2,37 @@ error[E0603]: module `bar` is private
   --> $DIR/privacy-in-paths.rs:24:16
    |
 LL |         ::foo::bar::baz::f();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `bar` is defined here
+  --> $DIR/privacy-in-paths.rs:3:5
+   |
+LL |     mod bar {
+   |     ^^^^^^^
 
 error[E0603]: module `bar` is private
   --> $DIR/privacy-in-paths.rs:25:16
    |
 LL |         ::foo::bar::S::f();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `bar` is defined here
+  --> $DIR/privacy-in-paths.rs:3:5
+   |
+LL |     mod bar {
+   |     ^^^^^^^
 
 error[E0603]: trait `T` is private
   --> $DIR/privacy-in-paths.rs:26:23
    |
 LL |         <() as ::foo::T>::Assoc::f();
-   |                       ^
+   |                       ^ this trait is private
+   |
+note: the trait `T` is defined here
+  --> $DIR/privacy-in-paths.rs:8:5
+   |
+LL |     trait T {
+   |     ^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr
index 2871573130a60..8b12109b37307 100644
--- a/src/test/ui/privacy/privacy-ns2.stderr
+++ b/src/test/ui/privacy/privacy-ns2.stderr
@@ -58,19 +58,37 @@ error[E0603]: trait `Bar` is private
   --> $DIR/privacy-ns2.rs:63:15
    |
 LL |     use foo3::Bar;
-   |               ^^^
+   |               ^^^ this trait is private
+   |
+note: the trait `Bar` is defined here
+  --> $DIR/privacy-ns2.rs:55:5
+   |
+LL |     trait Bar {
+   |     ^^^^^^^^^
 
 error[E0603]: trait `Bar` is private
   --> $DIR/privacy-ns2.rs:67:15
    |
 LL |     use foo3::Bar;
-   |               ^^^
+   |               ^^^ this trait is private
+   |
+note: the trait `Bar` is defined here
+  --> $DIR/privacy-ns2.rs:55:5
+   |
+LL |     trait Bar {
+   |     ^^^^^^^^^
 
 error[E0603]: trait `Bar` is private
   --> $DIR/privacy-ns2.rs:74:16
    |
 LL |     use foo3::{Bar,Baz};
-   |                ^^^
+   |                ^^^ this trait is private
+   |
+note: the trait `Bar` is defined here
+  --> $DIR/privacy-ns2.rs:55:5
+   |
+LL |     trait Bar {
+   |     ^^^^^^^^^
 
 error[E0107]: wrong number of const arguments: expected 0, found 1
   --> $DIR/privacy-ns2.rs:41:18
diff --git a/src/test/ui/privacy/privacy-ufcs.stderr b/src/test/ui/privacy/privacy-ufcs.stderr
index 6be14df89d20a..08640b802a244 100644
--- a/src/test/ui/privacy/privacy-ufcs.stderr
+++ b/src/test/ui/privacy/privacy-ufcs.stderr
@@ -2,7 +2,13 @@ error[E0603]: trait `Bar` is private
   --> $DIR/privacy-ufcs.rs:12:20
    |
 LL |     <i32 as ::foo::Bar>::baz();
-   |                    ^^^
+   |                    ^^^ this trait is private
+   |
+note: the trait `Bar` is defined here
+  --> $DIR/privacy-ufcs.rs:4:5
+   |
+LL |     trait Bar {
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/privacy/privacy1.stderr b/src/test/ui/privacy/privacy1.stderr
index 29f53cd0e3545..215df0dc75441 100644
--- a/src/test/ui/privacy/privacy1.stderr
+++ b/src/test/ui/privacy/privacy1.stderr
@@ -2,79 +2,157 @@ error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:132:18
    |
 LL |         use bar::baz::{foo, bar};
-   |                  ^^^
+   |                  ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:132:18
    |
 LL |         use bar::baz::{foo, bar};
-   |                  ^^^
+   |                  ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:141:18
    |
 LL |         use bar::baz;
-   |                  ^^^
+   |                  ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `i` is private
   --> $DIR/privacy1.rs:165:20
    |
 LL |     use self::foo::i::A;
-   |                    ^
+   |                    ^ this module is private
+   |
+note: the module `i` is defined here
+  --> $DIR/privacy1.rs:170:9
+   |
+LL |         mod i {
+   |         ^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:104:16
    |
 LL |         ::bar::baz::A::foo();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:105:16
    |
 LL |         ::bar::baz::A::bar();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:107:16
    |
 LL |         ::bar::baz::A.foo2();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:108:16
    |
 LL |         ::bar::baz::A.bar2();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: trait `B` is private
   --> $DIR/privacy1.rs:112:16
    |
 LL |         ::bar::B::foo();
-   |                ^
+   |                ^ this trait is private
+   |
+note: the trait `B` is defined here
+  --> $DIR/privacy1.rs:40:5
+   |
+LL |     trait B {
+   |     ^^^^^^^
 
 error[E0603]: function `epriv` is private
   --> $DIR/privacy1.rs:118:20
    |
 LL |             ::bar::epriv();
-   |                    ^^^^^
+   |                    ^^^^^ this function is private
+   |
+note: the function `epriv` is defined here
+  --> $DIR/privacy1.rs:65:9
+   |
+LL |         fn epriv();
+   |         ^^^^^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:127:16
    |
 LL |         ::bar::baz::foo();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: module `baz` is private
   --> $DIR/privacy1.rs:128:16
    |
 LL |         ::bar::baz::bar();
-   |                ^^^
+   |                ^^^ this module is private
+   |
+note: the module `baz` is defined here
+  --> $DIR/privacy1.rs:50:5
+   |
+LL |     mod baz {
+   |     ^^^^^^^
 
 error[E0603]: trait `B` is private
   --> $DIR/privacy1.rs:157:17
    |
 LL |     impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } }
-   |                 ^
+   |                 ^ this trait is private
+   |
+note: the trait `B` is defined here
+  --> $DIR/privacy1.rs:40:5
+   |
+LL |     trait B {
+   |     ^^^^^^^
 
 error[E0624]: method `bar` is private
   --> $DIR/privacy1.rs:77:9
diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr
index 9f2359657bd7c..d9f003ddae7ac 100644
--- a/src/test/ui/privacy/privacy2.stderr
+++ b/src/test/ui/privacy/privacy2.stderr
@@ -8,7 +8,13 @@ error[E0603]: function `foo` is private
   --> $DIR/privacy2.rs:23:20
    |
 LL |     use bar::glob::foo;
-   |                    ^^^
+   |                    ^^^ this function is private
+   |
+note: the function `foo` is defined here
+  --> $DIR/privacy2.rs:10:13
+   |
+LL |         use foo;
+   |             ^^^
 
 error: requires `sized` lang_item
 
diff --git a/src/test/ui/privacy/privacy4.stderr b/src/test/ui/privacy/privacy4.stderr
index e4a20f920a062..e34b2d5049b9e 100644
--- a/src/test/ui/privacy/privacy4.stderr
+++ b/src/test/ui/privacy/privacy4.stderr
@@ -2,7 +2,13 @@ error[E0603]: module `glob` is private
   --> $DIR/privacy4.rs:21:14
    |
 LL |     use bar::glob::gpriv;
-   |              ^^^^
+   |              ^^^^ this module is private
+   |
+note: the module `glob` is defined here
+  --> $DIR/privacy4.rs:13:5
+   |
+LL |     mod glob {
+   |     ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/privacy/privacy5.stderr b/src/test/ui/privacy/privacy5.stderr
index 2ee83149b695f..197a857cc3dc4 100644
--- a/src/test/ui/privacy/privacy5.stderr
+++ b/src/test/ui/privacy/privacy5.stderr
@@ -5,7 +5,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     let a = a::A(());
-   |                ^
+   |                ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:52:16
@@ -14,7 +20,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     let b = a::B(2);
-   |                ^
+   |                ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:53:16
@@ -23,7 +35,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let c = a::C(2, 3);
-   |                ^
+   |                ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:56:12
@@ -32,7 +50,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     let a::A(()) = a;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:57:12
@@ -41,7 +65,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     let a::A(_) = a;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:58:18
@@ -50,7 +80,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     match a { a::A(()) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:59:18
@@ -59,7 +95,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     match a { a::A(_) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:61:12
@@ -68,7 +110,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     let a::B(_) = b;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:62:12
@@ -77,7 +125,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     let a::B(_b) = b;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:63:18
@@ -86,7 +140,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     match b { a::B(_) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:64:18
@@ -95,7 +155,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     match b { a::B(_b) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:65:18
@@ -104,7 +170,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     match b { a::B(1) => {} a::B(_) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:65:32
@@ -113,7 +185,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     match b { a::B(1) => {} a::B(_) => {} }
-   |                                ^
+   |                                ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:68:12
@@ -122,7 +200,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let a::C(_, _) = c;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:69:12
@@ -131,7 +215,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let a::C(_a, _) = c;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:70:12
@@ -140,7 +230,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let a::C(_, _b) = c;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:71:12
@@ -149,7 +245,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let a::C(_a, _b) = c;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:72:18
@@ -158,7 +260,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     match c { a::C(_, _) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:73:18
@@ -167,7 +275,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     match c { a::C(_a, _) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:74:18
@@ -176,7 +290,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     match c { a::C(_, _b) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:75:18
@@ -185,7 +305,13 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     match c { a::C(_a, _b) => {} }
-   |                  ^
+   |                  ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:83:17
@@ -194,7 +320,13 @@ LL |     pub struct A(());
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     let a2 = a::A;
-   |                 ^
+   |                 ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/privacy5.rs:6:5
+   |
+LL |     pub struct A(());
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:84:17
@@ -203,7 +335,13 @@ LL |     pub struct B(isize);
    |                  ----- a constructor is private if any of the fields is private
 ...
 LL |     let b2 = a::B;
-   |                 ^
+   |                 ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/privacy5.rs:7:5
+   |
+LL |     pub struct B(isize);
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:85:17
@@ -212,271 +350,421 @@ LL |     pub struct C(pub isize, isize);
    |                  ---------------- a constructor is private if any of the fields is private
 ...
 LL |     let c2 = a::C;
-   |                 ^
+   |                 ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/privacy5.rs:8:5
+   |
+LL |     pub struct C(pub isize, isize);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:90:20
    |
 LL |     let a = other::A(());
-   |                    ^
+   |                    ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:91:20
    |
 LL |     let b = other::B(2);
-   |                    ^
+   |                    ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:92:20
    |
 LL |     let c = other::C(2, 3);
-   |                    ^
+   |                    ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:95:16
    |
 LL |     let other::A(()) = a;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:96:16
    |
 LL |     let other::A(_) = a;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:97:22
    |
 LL |     match a { other::A(()) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:98:22
    |
 LL |     match a { other::A(_) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:100:16
    |
 LL |     let other::B(_) = b;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:101:16
    |
 LL |     let other::B(_b) = b;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:102:22
    |
 LL |     match b { other::B(_) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:103:22
    |
 LL |     match b { other::B(_b) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:104:22
    |
 LL |     match b { other::B(1) => {}
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:105:16
    |
 LL |         other::B(_) => {} }
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:107:16
    |
 LL |     let other::C(_, _) = c;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:108:16
    |
 LL |     let other::C(_a, _) = c;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:109:16
    |
 LL |     let other::C(_, _b) = c;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:110:16
    |
 LL |     let other::C(_a, _b) = c;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:111:22
    |
 LL |     match c { other::C(_, _) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:112:22
    |
 LL |     match c { other::C(_a, _) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:113:22
    |
 LL |     match c { other::C(_, _b) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:114:22
    |
 LL |     match c { other::C(_a, _b) => {} }
-   |                      ^
+   |                      ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `A` is private
   --> $DIR/privacy5.rs:122:21
    |
 LL |     let a2 = other::A;
-   |                     ^
+   |                     ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
    |              -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `A` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1
+   |
+LL | pub struct A(());
+   | ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `B` is private
   --> $DIR/privacy5.rs:123:21
    |
 LL |     let b2 = other::B;
-   |                     ^
+   |                     ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
    |              ----- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `B` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1
+   |
+LL | pub struct B(isize);
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `C` is private
   --> $DIR/privacy5.rs:124:21
    |
 LL |     let c2 = other::C;
-   |                     ^
+   |                     ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
    |              ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `C` is defined here
+  --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1
+   |
+LL | pub struct C(pub isize, isize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 48 previous errors
 
diff --git a/src/test/ui/privacy/private-item-simple.stderr b/src/test/ui/privacy/private-item-simple.stderr
index 0d5435e1c504b..f51b74f6cb53b 100644
--- a/src/test/ui/privacy/private-item-simple.stderr
+++ b/src/test/ui/privacy/private-item-simple.stderr
@@ -2,7 +2,13 @@ error[E0603]: function `f` is private
   --> $DIR/private-item-simple.rs:6:8
    |
 LL |     a::f();
-   |        ^
+   |        ^ this function is private
+   |
+note: the function `f` is defined here
+  --> $DIR/private-item-simple.rs:2:5
+   |
+LL |     fn f() {}
+   |     ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr
index e6a61fbefb0d8..aac444b8e3c98 100644
--- a/src/test/ui/privacy/restricted/test.stderr
+++ b/src/test/ui/privacy/restricted/test.stderr
@@ -26,13 +26,25 @@ error[E0603]: struct `Crate` is private
   --> $DIR/test.rs:38:25
    |
 LL |     use pub_restricted::Crate;
-   |                         ^^^^^
+   |                         ^^^^^ this struct is private
+   |
+note: the struct `Crate` is defined here
+  --> $DIR/auxiliary/pub_restricted.rs:3:1
+   |
+LL | pub(crate) struct Crate;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: function `f` is private
   --> $DIR/test.rs:30:19
    |
 LL |     use foo::bar::f;
-   |                   ^
+   |                   ^ this function is private
+   |
+note: the function `f` is defined here
+  --> $DIR/test.rs:8:9
+   |
+LL |         pub(super) fn f() {}
+   |         ^^^^^^^^^^^^^^^^^
 
 error[E0616]: field `x` of struct `foo::bar::S` is private
   --> $DIR/test.rs:31:5
diff --git a/src/test/ui/proc-macro/disappearing-resolution.stderr b/src/test/ui/proc-macro/disappearing-resolution.stderr
index a3377ef515f91..d81ab5ebf9bc6 100644
--- a/src/test/ui/proc-macro/disappearing-resolution.stderr
+++ b/src/test/ui/proc-macro/disappearing-resolution.stderr
@@ -8,7 +8,13 @@ error[E0603]: derive macro `Empty` is private
   --> $DIR/disappearing-resolution.rs:11:8
    |
 LL | use m::Empty;
-   |        ^^^^^
+   |        ^^^^^ this derive macro is private
+   |
+note: the derive macro `Empty` is defined here
+  --> $DIR/disappearing-resolution.rs:9:9
+   |
+LL |     use test_macros::Empty;
+   |         ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/reachable/unreachable-variant.stderr b/src/test/ui/reachable/unreachable-variant.stderr
index 276c77f9b4249..c2e1d774e28ac 100644
--- a/src/test/ui/reachable/unreachable-variant.stderr
+++ b/src/test/ui/reachable/unreachable-variant.stderr
@@ -2,7 +2,13 @@ error[E0603]: module `super_sekrit` is private
   --> $DIR/unreachable-variant.rs:6:21
    |
 LL |     let _x = other::super_sekrit::sooper_sekrit::baz;
-   |                     ^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^ this module is private
+   |
+note: the module `super_sekrit` is defined here
+  --> $DIR/auxiliary/unreachable_variant.rs:1:1
+   |
+LL | mod super_sekrit {
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 688720e8cd388..08a1d790197a6 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -253,25 +253,49 @@ error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:57:22
    |
 LL |     let _: Z = m::n::Z;
-   |                      ^
+   |                      ^ this enum is private
+   |
+note: the enum `Z` is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:61:22
    |
 LL |     let _: Z = m::n::Z::Fn;
-   |                      ^
+   |                      ^ this enum is private
+   |
+note: the enum `Z` is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:64:22
    |
 LL |     let _: Z = m::n::Z::Struct;
-   |                      ^
+   |                      ^ this enum is private
+   |
+note: the enum `Z` is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:68:22
    |
 LL |     let _: Z = m::n::Z::Unit {};
-   |                      ^
+   |                      ^ this enum is private
+   |
+note: the enum `Z` is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
+   |
+LL |         pub(in m) enum Z {
+   |         ^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:27:20
diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr
index f1a1de4d9c0fd..1673ec46ba488 100644
--- a/src/test/ui/resolve/privacy-struct-ctor.stderr
+++ b/src/test/ui/resolve/privacy-struct-ctor.stderr
@@ -45,7 +45,13 @@ LL |         pub(in m) struct Z(pub(in m::n) u8);
    |                            --------------- a constructor is private if any of the fields is private
 ...
 LL |         n::Z;
-   |            ^
+   |            ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `Z` is defined here
+  --> $DIR/privacy-struct-ctor.rs:12:9
+   |
+LL |         pub(in m) struct Z(pub(in m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:29:8
@@ -54,7 +60,13 @@ LL |     pub struct S(u8);
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     m::S;
-   |        ^
+   |        ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `S` is defined here
+  --> $DIR/privacy-struct-ctor.rs:6:5
+   |
+LL |     pub struct S(u8);
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:31:19
@@ -63,7 +75,13 @@ LL |     pub struct S(u8);
    |                  -- a constructor is private if any of the fields is private
 ...
 LL |     let _: S = m::S(2);
-   |                   ^
+   |                   ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `S` is defined here
+  --> $DIR/privacy-struct-ctor.rs:6:5
+   |
+LL |     pub struct S(u8);
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `Z` is private
   --> $DIR/privacy-struct-ctor.rs:35:11
@@ -72,29 +90,47 @@ LL |         pub(in m) struct Z(pub(in m::n) u8);
    |                            --------------- a constructor is private if any of the fields is private
 ...
 LL |     m::n::Z;
-   |           ^
+   |           ^ this tuple struct constructor is private
+   |
+note: the tuple struct constructor `Z` is defined here
+  --> $DIR/privacy-struct-ctor.rs:12:9
+   |
+LL |         pub(in m) struct Z(pub(in m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `S` is private
   --> $DIR/privacy-struct-ctor.rs:41:16
    |
 LL |     xcrate::m::S;
-   |                ^
+   |                ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy-struct-ctor.rs:2:18
    |
 LL |     pub struct S(u8);
    |                  -- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `S` is defined here
+  --> $DIR/auxiliary/privacy-struct-ctor.rs:2:5
+   |
+LL |     pub struct S(u8);
+   |     ^^^^^^^^^^^^^^^^^
 
 error[E0603]: tuple struct constructor `Z` is private
   --> $DIR/privacy-struct-ctor.rs:45:19
    |
 LL |     xcrate::m::n::Z;
-   |                   ^
+   |                   ^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:28
    |
 LL |         pub(in m) struct Z(pub(in m::n) u8);
    |                            --------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `Z` is defined here
+  --> $DIR/auxiliary/privacy-struct-ctor.rs:5:9
+   |
+LL |         pub(in m) struct Z(pub(in m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
index 944965a15e3d0..f992988c93fcc 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
@@ -14,18 +14,30 @@ error[E0603]: tuple struct constructor `TupleStruct` is private
   --> $DIR/struct.rs:23:32
    |
 LL |     let ts_explicit = structs::TupleStruct(640, 480);
-   |                                ^^^^^^^^^^^
+   |                                ^^^^^^^^^^^ this tuple struct constructor is private
    | 
   ::: $DIR/auxiliary/structs.rs:11:24
    |
 LL | pub struct TupleStruct(pub u16, pub u16);
    |                        ---------------- a constructor is private if any of the fields is private
+   |
+note: the tuple struct constructor `TupleStruct` is defined here
+  --> $DIR/auxiliary/structs.rs:11:1
+   |
+LL | pub struct TupleStruct(pub u16, pub u16);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: unit struct `UnitStruct` is private
   --> $DIR/struct.rs:32:32
    |
 LL |     let us_explicit = structs::UnitStruct;
-   |                                ^^^^^^^^^^
+   |                                ^^^^^^^^^^ this unit struct is private
+   |
+note: the unit struct `UnitStruct` is defined here
+  --> $DIR/auxiliary/structs.rs:8:1
+   |
+LL | pub struct UnitStruct;
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0639]: cannot create non-exhaustive struct using struct expression
   --> $DIR/struct.rs:7:14
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
index d9d6ea21b8bd4..2a438753a2c70 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
@@ -2,31 +2,61 @@ error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:11:48
    |
 LL |     let variant_tuple = NonExhaustiveVariants::Tuple(640);
-   |                                                ^^^^^
+   |                                                ^^^^^ this tuple variant is private
+   |
+note: the tuple variant `Tuple` is defined here
+  --> $DIR/auxiliary/variants.rs:5:23
+   |
+LL |     #[non_exhaustive] Tuple(u32),
+   |                       ^^^^^^^^^^
 
 error[E0603]: unit variant `Unit` is private
   --> $DIR/variant.rs:14:47
    |
 LL |     let variant_unit = NonExhaustiveVariants::Unit;
-   |                                               ^^^^
+   |                                               ^^^^ this unit variant is private
+   |
+note: the unit variant `Unit` is defined here
+  --> $DIR/auxiliary/variants.rs:4:23
+   |
+LL |     #[non_exhaustive] Unit,
+   |                       ^^^^
 
 error[E0603]: unit variant `Unit` is private
   --> $DIR/variant.rs:18:32
    |
 LL |         NonExhaustiveVariants::Unit => "",
-   |                                ^^^^
+   |                                ^^^^ this unit variant is private
+   |
+note: the unit variant `Unit` is defined here
+  --> $DIR/auxiliary/variants.rs:4:23
+   |
+LL |     #[non_exhaustive] Unit,
+   |                       ^^^^
 
 error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:20:32
    |
 LL |         NonExhaustiveVariants::Tuple(fe_tpl) => "",
-   |                                ^^^^^
+   |                                ^^^^^ this tuple variant is private
+   |
+note: the tuple variant `Tuple` is defined here
+  --> $DIR/auxiliary/variants.rs:5:23
+   |
+LL |     #[non_exhaustive] Tuple(u32),
+   |                       ^^^^^^^^^^
 
 error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:26:35
    |
 LL |     if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
-   |                                   ^^^^^
+   |                                   ^^^^^ this tuple variant is private
+   |
+note: the tuple variant `Tuple` is defined here
+  --> $DIR/auxiliary/variants.rs:5:23
+   |
+LL |     #[non_exhaustive] Tuple(u32),
+   |                       ^^^^^^^^^^
 
 error[E0639]: cannot create non-exhaustive variant using struct expression
   --> $DIR/variant.rs:8:26
diff --git a/src/test/ui/shadowed/shadowed-use-visibility.stderr b/src/test/ui/shadowed/shadowed-use-visibility.stderr
index 7c66fdf60b1d4..77bf2abe34555 100644
--- a/src/test/ui/shadowed/shadowed-use-visibility.stderr
+++ b/src/test/ui/shadowed/shadowed-use-visibility.stderr
@@ -2,13 +2,25 @@ error[E0603]: module `bar` is private
   --> $DIR/shadowed-use-visibility.rs:9:14
    |
 LL |     use foo::bar::f as g;
-   |              ^^^
+   |              ^^^ this module is private
+   |
+note: the module `bar` is defined here
+  --> $DIR/shadowed-use-visibility.rs:4:9
+   |
+LL |     use foo as bar;
+   |         ^^^^^^^^^^
 
 error[E0603]: module `f` is private
   --> $DIR/shadowed-use-visibility.rs:15:10
    |
 LL | use bar::f::f;
-   |          ^
+   |          ^ this module is private
+   |
+note: the module `f` is defined here
+  --> $DIR/shadowed-use-visibility.rs:11:9
+   |
+LL |     use foo as f;
+   |         ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/stability-in-private-module.stderr b/src/test/ui/stability-in-private-module.stderr
index c3edd62a15eda..537a400664aaa 100644
--- a/src/test/ui/stability-in-private-module.stderr
+++ b/src/test/ui/stability-in-private-module.stderr
@@ -2,7 +2,13 @@ error[E0603]: module `thread_info` is private
   --> $DIR/stability-in-private-module.rs:2:26
    |
 LL |     let _ = std::thread::thread_info::current_thread();
-   |                          ^^^^^^^^^^^
+   |                          ^^^^^^^^^^^ this module is private
+   |
+note: the module `thread_info` is defined here
+  --> $SRC_DIR/libstd/thread/mod.rs:LL:COL
+   |
+LL | use crate::sys_common::thread_info;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/static/static-priv-by-default2.stderr b/src/test/ui/static/static-priv-by-default2.stderr
index 95bcf07633565..f6cd40412dd84 100644
--- a/src/test/ui/static/static-priv-by-default2.stderr
+++ b/src/test/ui/static/static-priv-by-default2.stderr
@@ -2,13 +2,25 @@ error[E0603]: static `private` is private
   --> $DIR/static-priv-by-default2.rs:15:30
    |
 LL |     use child::childs_child::private;
-   |                              ^^^^^^^
+   |                              ^^^^^^^ this static is private
+   |
+note: the static `private` is defined here
+  --> $DIR/static-priv-by-default2.rs:7:9
+   |
+LL |         static private: isize = 0;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: static `private` is private
   --> $DIR/static-priv-by-default2.rs:23:33
    |
 LL |     use static_priv_by_default::private;
-   |                                 ^^^^^^^
+   |                                 ^^^^^^^ this static is private
+   |
+note: the static `private` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:3:1
+   |
+LL | static private: isize = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/structs/struct-variant-privacy-xc.stderr b/src/test/ui/structs/struct-variant-privacy-xc.stderr
index 39241b6b3fc1d..0203b7b5242e5 100644
--- a/src/test/ui/structs/struct-variant-privacy-xc.stderr
+++ b/src/test/ui/structs/struct-variant-privacy-xc.stderr
@@ -2,13 +2,25 @@ error[E0603]: enum `Bar` is private
   --> $DIR/struct-variant-privacy-xc.rs:4:33
    |
 LL | fn f(b: struct_variant_privacy::Bar) {
-   |                                 ^^^
+   |                                 ^^^ this enum is private
+   |
+note: the enum `Bar` is defined here
+  --> $DIR/auxiliary/struct_variant_privacy.rs:1:1
+   |
+LL | enum Bar {
+   | ^^^^^^^^
 
 error[E0603]: enum `Bar` is private
   --> $DIR/struct-variant-privacy-xc.rs:6:33
    |
 LL |         struct_variant_privacy::Bar::Baz { a: _a } => {}
-   |                                 ^^^
+   |                                 ^^^ this enum is private
+   |
+note: the enum `Bar` is defined here
+  --> $DIR/auxiliary/struct_variant_privacy.rs:1:1
+   |
+LL | enum Bar {
+   | ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/structs/struct-variant-privacy.stderr b/src/test/ui/structs/struct-variant-privacy.stderr
index 127a650104485..d1b603f9d46fc 100644
--- a/src/test/ui/structs/struct-variant-privacy.stderr
+++ b/src/test/ui/structs/struct-variant-privacy.stderr
@@ -2,13 +2,25 @@ error[E0603]: enum `Bar` is private
   --> $DIR/struct-variant-privacy.rs:7:14
    |
 LL | fn f(b: foo::Bar) {
-   |              ^^^
+   |              ^^^ this enum is private
+   |
+note: the enum `Bar` is defined here
+  --> $DIR/struct-variant-privacy.rs:2:5
+   |
+LL |     enum Bar {
+   |     ^^^^^^^^
 
 error[E0603]: enum `Bar` is private
   --> $DIR/struct-variant-privacy.rs:9:14
    |
 LL |         foo::Bar::Baz { a: _a } => {}
-   |              ^^^
+   |              ^^^ this enum is private
+   |
+note: the enum `Bar` is defined here
+  --> $DIR/struct-variant-privacy.rs:2:5
+   |
+LL |     enum Bar {
+   |     ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/use/use-from-trait-xc.stderr b/src/test/ui/use/use-from-trait-xc.stderr
index f7438cce22967..3f38a6cae7b81 100644
--- a/src/test/ui/use/use-from-trait-xc.stderr
+++ b/src/test/ui/use/use-from-trait-xc.stderr
@@ -44,13 +44,25 @@ error[E0603]: struct `Foo` is private
   --> $DIR/use-from-trait-xc.rs:14:24
    |
 LL | use use_from_trait_xc::Foo::new;
-   |                        ^^^
+   |                        ^^^ this struct is private
+   |
+note: the struct `Foo` is defined here
+  --> $DIR/auxiliary/use-from-trait-xc.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^^
 
 error[E0603]: struct `Foo` is private
   --> $DIR/use-from-trait-xc.rs:17:24
    |
 LL | use use_from_trait_xc::Foo::C;
-   |                        ^^^
+   |                        ^^^ this struct is private
+   |
+note: the struct `Foo` is defined here
+  --> $DIR/auxiliary/use-from-trait-xc.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/use/use-mod/use-mod-3.stderr b/src/test/ui/use/use-mod/use-mod-3.stderr
index 0c800ec35e409..4852759286ae6 100644
--- a/src/test/ui/use/use-mod/use-mod-3.stderr
+++ b/src/test/ui/use/use-mod/use-mod-3.stderr
@@ -2,13 +2,25 @@ error[E0603]: module `bar` is private
   --> $DIR/use-mod-3.rs:1:10
    |
 LL | use foo::bar::{
-   |          ^^^
+   |          ^^^ this module is private
+   |
+note: the module `bar` is defined here
+  --> $DIR/use-mod-3.rs:9:5
+   |
+LL |     mod bar { pub type Bar = isize; }
+   |     ^^^^^^^
 
 error[E0603]: module `bar` is private
   --> $DIR/use-mod-3.rs:4:10
    |
 LL | use foo::bar::{
-   |          ^^^
+   |          ^^^ this module is private
+   |
+note: the module `bar` is defined here
+  --> $DIR/use-mod-3.rs:9:5
+   |
+LL |     mod bar { pub type Bar = isize; }
+   |     ^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/xcrate/xcrate-private-by-default.stderr b/src/test/ui/xcrate/xcrate-private-by-default.stderr
index da52b4249e319..842069d6135cb 100644
--- a/src/test/ui/xcrate/xcrate-private-by-default.stderr
+++ b/src/test/ui/xcrate/xcrate-private-by-default.stderr
@@ -2,61 +2,121 @@ error[E0603]: static `j` is private
   --> $DIR/xcrate-private-by-default.rs:23:29
    |
 LL |     static_priv_by_default::j;
-   |                             ^
+   |                             ^ this static is private
+   |
+note: the static `j` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:47:1
+   |
+LL | static j: isize = 0;
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: function `k` is private
   --> $DIR/xcrate-private-by-default.rs:25:29
    |
 LL |     static_priv_by_default::k;
-   |                             ^
+   |                             ^ this function is private
+   |
+note: the function `k` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:48:1
+   |
+LL | fn k() {}
+   | ^^^^^^
 
 error[E0603]: unit struct `l` is private
   --> $DIR/xcrate-private-by-default.rs:27:29
    |
 LL |     static_priv_by_default::l;
-   |                             ^
+   |                             ^ this unit struct is private
+   |
+note: the unit struct `l` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:49:1
+   |
+LL | struct l;
+   | ^^^^^^^^^
 
 error[E0603]: enum `m` is private
   --> $DIR/xcrate-private-by-default.rs:29:35
    |
 LL |     foo::<static_priv_by_default::m>();
-   |                                   ^
+   |                                   ^ this enum is private
+   |
+note: the enum `m` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:50:1
+   |
+LL | enum m {}
+   | ^^^^^^
 
 error[E0603]: type alias `n` is private
   --> $DIR/xcrate-private-by-default.rs:31:35
    |
 LL |     foo::<static_priv_by_default::n>();
-   |                                   ^
+   |                                   ^ this type alias is private
+   |
+note: the type alias `n` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:51:1
+   |
+LL | type n = isize;
+   | ^^^^^^^^^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/xcrate-private-by-default.rs:35:29
    |
 LL |     static_priv_by_default::foo::a;
-   |                             ^^^
+   |                             ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:12:1
+   |
+LL | mod foo {
+   | ^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/xcrate-private-by-default.rs:37:29
    |
 LL |     static_priv_by_default::foo::b;
-   |                             ^^^
+   |                             ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:12:1
+   |
+LL | mod foo {
+   | ^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/xcrate-private-by-default.rs:39:29
    |
 LL |     static_priv_by_default::foo::c;
-   |                             ^^^
+   |                             ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:12:1
+   |
+LL | mod foo {
+   | ^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/xcrate-private-by-default.rs:41:35
    |
 LL |     foo::<static_priv_by_default::foo::d>();
-   |                                   ^^^
+   |                                   ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:12:1
+   |
+LL | mod foo {
+   | ^^^^^^^
 
 error[E0603]: module `foo` is private
   --> $DIR/xcrate-private-by-default.rs:43:35
    |
 LL |     foo::<static_priv_by_default::foo::e>();
-   |                                   ^^^
+   |                                   ^^^ this module is private
+   |
+note: the module `foo` is defined here
+  --> $DIR/auxiliary/static_priv_by_default.rs:12:1
+   |
+LL | mod foo {
+   | ^^^^^^^
 
 error: aborting due to 10 previous errors
 

From c84efe9b6ca05f64d8b925acc2724971d186f8f6 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 12 Jan 2020 16:20:57 +0300
Subject: [PATCH 21/25] resolve: Say "import" when reporting private imports

---
 src/librustc_resolve/diagnostics.rs                  |  3 +++
 src/test/ui/extern/extern-crate-visibility.rs        |  4 ++--
 src/test/ui/extern/extern-crate-visibility.stderr    | 12 ++++++------
 src/test/ui/import.stderr                            |  6 +++---
 src/test/ui/imports/issue-55884-2.rs                 |  2 +-
 src/test/ui/imports/issue-55884-2.stderr             |  6 +++---
 src/test/ui/imports/reexports.stderr                 | 12 ++++++------
 src/test/ui/privacy/privacy2.stderr                  |  6 +++---
 src/test/ui/proc-macro/disappearing-resolution.rs    |  2 +-
 .../ui/proc-macro/disappearing-resolution.stderr     |  6 +++---
 src/test/ui/shadowed/shadowed-use-visibility.rs      |  4 ++--
 src/test/ui/shadowed/shadowed-use-visibility.stderr  | 12 ++++++------
 12 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 20c8f78b1cf0e..a433ae8ed676a 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -921,6 +921,9 @@ impl<'a> Resolver<'a> {
             if is_constructor {
                 descr += " constructor";
             }
+            if binding.is_import() {
+                descr += " import";
+            }
 
             let mut err =
                 struct_span_err!(session, ident.span, E0603, "{} `{}` is private", descr, ident);
diff --git a/src/test/ui/extern/extern-crate-visibility.rs b/src/test/ui/extern/extern-crate-visibility.rs
index e0a5cd5e98f4b..cda1227cc8e92 100644
--- a/src/test/ui/extern/extern-crate-visibility.rs
+++ b/src/test/ui/extern/extern-crate-visibility.rs
@@ -3,10 +3,10 @@ mod foo {
 }
 
 // Check that private crates can be used from outside their modules, albeit with warnings
-use foo::core::cell; //~ ERROR crate `core` is private
+use foo::core::cell; //~ ERROR crate import `core` is private
 
 fn f() {
-    foo::core::cell::Cell::new(0); //~ ERROR crate `core` is private
+    foo::core::cell::Cell::new(0); //~ ERROR crate import `core` is private
 
     use foo::*;
     mod core {} // Check that private crates are not glob imported
diff --git a/src/test/ui/extern/extern-crate-visibility.stderr b/src/test/ui/extern/extern-crate-visibility.stderr
index 6d38b4d8d66d6..d0c073d67a4ee 100644
--- a/src/test/ui/extern/extern-crate-visibility.stderr
+++ b/src/test/ui/extern/extern-crate-visibility.stderr
@@ -1,22 +1,22 @@
-error[E0603]: crate `core` is private
+error[E0603]: crate import `core` is private
   --> $DIR/extern-crate-visibility.rs:6:10
    |
 LL | use foo::core::cell;
-   |          ^^^^ this crate is private
+   |          ^^^^ this crate import is private
    |
-note: the crate `core` is defined here
+note: the crate import `core` is defined here
   --> $DIR/extern-crate-visibility.rs:2:5
    |
 LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^
 
-error[E0603]: crate `core` is private
+error[E0603]: crate import `core` is private
   --> $DIR/extern-crate-visibility.rs:9:10
    |
 LL |     foo::core::cell::Cell::new(0);
-   |          ^^^^ this crate is private
+   |          ^^^^ this crate import is private
    |
-note: the crate `core` is defined here
+note: the crate import `core` is defined here
   --> $DIR/extern-crate-visibility.rs:2:5
    |
 LL |     extern crate core;
diff --git a/src/test/ui/import.stderr b/src/test/ui/import.stderr
index c66a4fa7151dc..5219ffacd15c0 100644
--- a/src/test/ui/import.stderr
+++ b/src/test/ui/import.stderr
@@ -13,13 +13,13 @@ error[E0432]: unresolved import `foo`
 LL |     use foo;
    |         ^^^ no `foo` in the root
 
-error[E0603]: unresolved item `foo` is private
+error[E0603]: unresolved item import `foo` is private
   --> $DIR/import.rs:15:10
    |
 LL |     zed::foo();
-   |          ^^^ this unresolved item is private
+   |          ^^^ this unresolved item import is private
    |
-note: the unresolved item `foo` is defined here
+note: the unresolved item import `foo` is defined here
   --> $DIR/import.rs:10:9
    |
 LL |     use foo;
diff --git a/src/test/ui/imports/issue-55884-2.rs b/src/test/ui/imports/issue-55884-2.rs
index 1b4f652c9fc2f..75bb4206f97d6 100644
--- a/src/test/ui/imports/issue-55884-2.rs
+++ b/src/test/ui/imports/issue-55884-2.rs
@@ -9,6 +9,6 @@ mod parser {
     use ParseOptions;
 }
 
-pub use parser::ParseOptions; //~ ERROR struct `ParseOptions` is private
+pub use parser::ParseOptions; //~ ERROR struct import `ParseOptions` is private
 
 fn main() {}
diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr
index 9e77283cd5946..f16d2adb3656e 100644
--- a/src/test/ui/imports/issue-55884-2.stderr
+++ b/src/test/ui/imports/issue-55884-2.stderr
@@ -1,10 +1,10 @@
-error[E0603]: struct `ParseOptions` is private
+error[E0603]: struct import `ParseOptions` is private
   --> $DIR/issue-55884-2.rs:12:17
    |
 LL | pub use parser::ParseOptions;
-   |                 ^^^^^^^^^^^^ this struct is private
+   |                 ^^^^^^^^^^^^ this struct import is private
    |
-note: the struct `ParseOptions` is defined here
+note: the struct import `ParseOptions` is defined here
   --> $DIR/issue-55884-2.rs:9:9
    |
 LL |     use ParseOptions;
diff --git a/src/test/ui/imports/reexports.stderr b/src/test/ui/imports/reexports.stderr
index 67c12e0c8d3ca..b173884080f80 100644
--- a/src/test/ui/imports/reexports.stderr
+++ b/src/test/ui/imports/reexports.stderr
@@ -10,25 +10,25 @@ note: consider marking `foo` as `pub` in the imported module
 LL |         pub use super::foo;
    |                 ^^^^^^^^^^
 
-error[E0603]: module `foo` is private
+error[E0603]: module import `foo` is private
   --> $DIR/reexports.rs:33:15
    |
 LL |     use b::a::foo::S;
-   |               ^^^ this module is private
+   |               ^^^ this module import is private
    |
-note: the module `foo` is defined here
+note: the module import `foo` is defined here
   --> $DIR/reexports.rs:21:17
    |
 LL |         pub use super::foo; // This is OK since the value `foo` is visible enough.
    |                 ^^^^^^^^^^
 
-error[E0603]: module `foo` is private
+error[E0603]: module import `foo` is private
   --> $DIR/reexports.rs:34:15
    |
 LL |     use b::b::foo::S as T;
-   |               ^^^ this module is private
+   |               ^^^ this module import is private
    |
-note: the module `foo` is defined here
+note: the module import `foo` is defined here
   --> $DIR/reexports.rs:26:17
    |
 LL |         pub use super::*; // This is also OK since the value `foo` is visible enough.
diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr
index d9f003ddae7ac..719dc27ccf4d6 100644
--- a/src/test/ui/privacy/privacy2.stderr
+++ b/src/test/ui/privacy/privacy2.stderr
@@ -4,13 +4,13 @@ error[E0432]: unresolved import `bar::foo`
 LL |     use bar::foo;
    |         ^^^^^^^^ no `foo` in `bar`
 
-error[E0603]: function `foo` is private
+error[E0603]: function import `foo` is private
   --> $DIR/privacy2.rs:23:20
    |
 LL |     use bar::glob::foo;
-   |                    ^^^ this function is private
+   |                    ^^^ this function import is private
    |
-note: the function `foo` is defined here
+note: the function import `foo` is defined here
   --> $DIR/privacy2.rs:10:13
    |
 LL |         use foo;
diff --git a/src/test/ui/proc-macro/disappearing-resolution.rs b/src/test/ui/proc-macro/disappearing-resolution.rs
index a01b8f302cae3..50f04b1eae150 100644
--- a/src/test/ui/proc-macro/disappearing-resolution.rs
+++ b/src/test/ui/proc-macro/disappearing-resolution.rs
@@ -8,7 +8,7 @@ extern crate test_macros;
 mod m {
     use test_macros::Empty;
 }
-use m::Empty; //~ ERROR derive macro `Empty` is private
+use m::Empty; //~ ERROR derive macro import `Empty` is private
 
 // To resolve `empty_helper` we need to resolve `Empty`.
 // During initial resolution `use m::Empty` introduces no entries, so we proceed to `macro_use`,
diff --git a/src/test/ui/proc-macro/disappearing-resolution.stderr b/src/test/ui/proc-macro/disappearing-resolution.stderr
index d81ab5ebf9bc6..3beaedf61d73a 100644
--- a/src/test/ui/proc-macro/disappearing-resolution.stderr
+++ b/src/test/ui/proc-macro/disappearing-resolution.stderr
@@ -4,13 +4,13 @@ error: cannot find attribute `empty_helper` in this scope
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^
 
-error[E0603]: derive macro `Empty` is private
+error[E0603]: derive macro import `Empty` is private
   --> $DIR/disappearing-resolution.rs:11:8
    |
 LL | use m::Empty;
-   |        ^^^^^ this derive macro is private
+   |        ^^^^^ this derive macro import is private
    |
-note: the derive macro `Empty` is defined here
+note: the derive macro import `Empty` is defined here
   --> $DIR/disappearing-resolution.rs:9:9
    |
 LL |     use test_macros::Empty;
diff --git a/src/test/ui/shadowed/shadowed-use-visibility.rs b/src/test/ui/shadowed/shadowed-use-visibility.rs
index 8185e82ee830e..6b801972f4179 100644
--- a/src/test/ui/shadowed/shadowed-use-visibility.rs
+++ b/src/test/ui/shadowed/shadowed-use-visibility.rs
@@ -6,11 +6,11 @@ mod foo {
 }
 
 mod bar {
-    use foo::bar::f as g; //~ ERROR module `bar` is private
+    use foo::bar::f as g; //~ ERROR module import `bar` is private
 
     use foo as f;
     pub use foo::*;
 }
 
-use bar::f::f; //~ ERROR module `f` is private
+use bar::f::f; //~ ERROR module import `f` is private
 fn main() {}
diff --git a/src/test/ui/shadowed/shadowed-use-visibility.stderr b/src/test/ui/shadowed/shadowed-use-visibility.stderr
index 77bf2abe34555..cd8ec13794c6f 100644
--- a/src/test/ui/shadowed/shadowed-use-visibility.stderr
+++ b/src/test/ui/shadowed/shadowed-use-visibility.stderr
@@ -1,22 +1,22 @@
-error[E0603]: module `bar` is private
+error[E0603]: module import `bar` is private
   --> $DIR/shadowed-use-visibility.rs:9:14
    |
 LL |     use foo::bar::f as g;
-   |              ^^^ this module is private
+   |              ^^^ this module import is private
    |
-note: the module `bar` is defined here
+note: the module import `bar` is defined here
   --> $DIR/shadowed-use-visibility.rs:4:9
    |
 LL |     use foo as bar;
    |         ^^^^^^^^^^
 
-error[E0603]: module `f` is private
+error[E0603]: module import `f` is private
   --> $DIR/shadowed-use-visibility.rs:15:10
    |
 LL | use bar::f::f;
-   |          ^ this module is private
+   |          ^ this module import is private
    |
-note: the module `f` is defined here
+note: the module import `f` is defined here
   --> $DIR/shadowed-use-visibility.rs:11:9
    |
 LL |     use foo as f;

From 0b60f1f2ae54b0bdb1623606db5dd18da1e80517 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 16 Jan 2020 22:19:55 +0300
Subject: [PATCH 22/25] Ignore some tests on platforms without libstd spans

---
 src/test/ui/issues/issue-38857.rs              | 5 +++++
 src/test/ui/issues/issue-38857.stderr          | 4 ++--
 src/test/ui/stability-in-private-module.rs     | 5 +++++
 src/test/ui/stability-in-private-module.stderr | 2 +-
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/test/ui/issues/issue-38857.rs b/src/test/ui/issues/issue-38857.rs
index 81d881c100bb6..c0695f8216512 100644
--- a/src/test/ui/issues/issue-38857.rs
+++ b/src/test/ui/issues/issue-38857.rs
@@ -1,3 +1,8 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
+
 fn main() {
     let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() };
     //~^ ERROR failed to resolve: could not find `imp` in `sys` [E0433]
diff --git a/src/test/ui/issues/issue-38857.stderr b/src/test/ui/issues/issue-38857.stderr
index dd7970e014fdb..ba0f1336ff09d 100644
--- a/src/test/ui/issues/issue-38857.stderr
+++ b/src/test/ui/issues/issue-38857.stderr
@@ -1,11 +1,11 @@
 error[E0433]: failed to resolve: could not find `imp` in `sys`
-  --> $DIR/issue-38857.rs:2:23
+  --> $DIR/issue-38857.rs:7:23
    |
 LL |     let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() };
    |                       ^^^ could not find `imp` in `sys`
 
 error[E0603]: module `sys` is private
-  --> $DIR/issue-38857.rs:2:18
+  --> $DIR/issue-38857.rs:7:18
    |
 LL |     let a = std::sys::imp::process::process_common::StdioPipes { ..panic!() };
    |                  ^^^ this module is private
diff --git a/src/test/ui/stability-in-private-module.rs b/src/test/ui/stability-in-private-module.rs
index f12e9198b0d7c..1815897f17a60 100644
--- a/src/test/ui/stability-in-private-module.rs
+++ b/src/test/ui/stability-in-private-module.rs
@@ -1,3 +1,8 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
+
 fn main() {
     let _ = std::thread::thread_info::current_thread();
     //~^ERROR module `thread_info` is private
diff --git a/src/test/ui/stability-in-private-module.stderr b/src/test/ui/stability-in-private-module.stderr
index 537a400664aaa..3a974164f9473 100644
--- a/src/test/ui/stability-in-private-module.stderr
+++ b/src/test/ui/stability-in-private-module.stderr
@@ -1,5 +1,5 @@
 error[E0603]: module `thread_info` is private
-  --> $DIR/stability-in-private-module.rs:2:26
+  --> $DIR/stability-in-private-module.rs:7:26
    |
 LL |     let _ = std::thread::thread_info::current_thread();
    |                          ^^^^^^^^^^^ this module is private

From 029a9c625371e756d93024efd3deb7636a90f8f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 16 Jan 2020 11:32:50 -0800
Subject: [PATCH 23/25] review comments

---
 .../traits/error_reporting/suggestions.rs     | 49 +++++++++----------
 src/librustc_error_codes/error_codes/E0746.md |  2 +-
 2 files changed, 24 insertions(+), 27 deletions(-)

diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs
index c3af063d518f0..bf6891214ace1 100644
--- a/src/librustc/traits/error_reporting/suggestions.rs
+++ b/src/librustc/traits/error_reporting/suggestions.rs
@@ -605,34 +605,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
 
-        let mut all_returns_conform_to_trait = true;
-        let mut all_returns_have_same_type = true;
-        let mut last_ty = None;
-        if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
-            let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
-            let param_env = ty::ParamEnv::empty();
-            if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
-                for expr in &visitor.0 {
-                    if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
-                        all_returns_have_same_type &=
-                            Some(returned_ty) == last_ty || last_ty.is_none();
-                        last_ty = Some(returned_ty);
-                        for predicate in predicates.iter() {
-                            let pred = predicate.with_self_ty(self.tcx, returned_ty);
-                            let obl = Obligation::new(cause.clone(), param_env, pred);
-                            all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
-                        }
+        let mut ret_types = visitor.0.iter().filter_map(|expr| tables.node_type_opt(expr.hir_id));
+        let (last_ty, all_returns_have_same_type) =
+            ret_types.clone().fold((None, true), |(last_ty, mut same), returned_ty| {
+                same &= last_ty.map_or(true, |ty| ty == returned_ty);
+                (Some(returned_ty), same)
+            });
+        let all_returns_conform_to_trait =
+            if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
+                match ty_ret_ty.kind {
+                    ty::Dynamic(predicates, _) => {
+                        let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
+                        let param_env = ty::ParamEnv::empty();
+                        ret_types.all(|returned_ty| {
+                            predicates.iter().all(|predicate| {
+                                let pred = predicate.with_self_ty(self.tcx, returned_ty);
+                                let obl = Obligation::new(cause.clone(), param_env, pred);
+                                self.predicate_may_hold(&obl)
+                            })
+                        })
                     }
+                    _ => true,
                 }
-            }
-        } else {
-            // We still want to verify whether all the return types conform to each other.
-            for expr in &visitor.0 {
-                let returned_ty = tables.node_type_opt(expr.hir_id);
-                all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
-                last_ty = returned_ty;
-            }
-        }
+            } else {
+                true
+            };
 
         let (snippet, last_ty) =
             if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md
index 041061f3380c1..16b2722f0eac2 100644
--- a/src/librustc_error_codes/error_codes/E0746.md
+++ b/src/librustc_error_codes/error_codes/E0746.md
@@ -13,7 +13,7 @@ impl T for S {
 }
 
 // Having the trait `T` as return type is invalid because
-// bare trait objects do not have a statically known size:
+// unboxed trait objects do not have a statically known size:
 fn foo() -> dyn T {
     S(42)
 }

From 7fbd30b1ae0ce9293302bbf4bfb814f1dc791107 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= <matthias.krueger@famsik.de>
Date: Thu, 16 Jan 2020 23:15:52 +0100
Subject: [PATCH 24/25] don't clone types that are copy

found via clippy
---
 src/librustc/infer/error_reporting/mod.rs              | 2 +-
 src/librustc_ast_lowering/expr.rs                      | 6 +++---
 src/librustc_builtin_macros/deriving/generic/mod.rs    | 2 +-
 src/librustc_errors/annotate_snippet_emitter_writer.rs | 2 +-
 src/librustc_incremental/persist/save.rs               | 2 +-
 src/librustc_lint/context.rs                           | 2 +-
 src/librustc_metadata/rmeta/decoder.rs                 | 2 +-
 src/librustc_metadata/rmeta/encoder.rs                 | 2 +-
 src/librustc_mir/borrow_check/borrow_set.rs            | 4 ++--
 src/librustc_mir_build/build/mod.rs                    | 2 +-
 src/librustc_passes/stability.rs                       | 2 +-
 src/librustc_traits/chalk_context/mod.rs               | 2 +-
 src/librustc_typeck/check/closure.rs                   | 2 +-
 src/librustdoc/clean/auto_trait.rs                     | 2 +-
 src/libtest/lib.rs                                     | 4 +---
 15 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index c52d4335ea184..febf4f21a6755 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -2008,7 +2008,7 @@ impl<'tcx> ObligationCause<'tcx> {
                 TypeError::IntrinsicCast => {
                     Error0308("cannot coerce intrinsics to function pointers")
                 }
-                TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
+                TypeError::ObjectUnsafeCoercion(did) => Error0038(*did),
                 _ => Error0308("mismatched types"),
             },
         }
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index 9a229e709a5e5..2866a1624de5b 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -909,18 +909,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind<'hir> {
         let inner = hir::InlineAsmInner {
-            inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
+            inputs: asm.inputs.iter().map(|&(c, _)| c).collect(),
             outputs: asm
                 .outputs
                 .iter()
                 .map(|out| hir::InlineAsmOutput {
-                    constraint: out.constraint.clone(),
+                    constraint: out.constraint,
                     is_rw: out.is_rw,
                     is_indirect: out.is_indirect,
                     span: out.expr.span,
                 })
                 .collect(),
-            asm: asm.asm.clone(),
+            asm: asm.asm,
             asm_str_style: asm.asm_str_style,
             clobbers: asm.clobbers.clone().into(),
             volatile: asm.volatile,
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index 7092483843f70..9226f45816506 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -1608,7 +1608,7 @@ impl<'a> TraitDef<'a> {
                 } else {
                     ast::BindingMode::ByRef(mutbl)
                 };
-                cx.pat(path.span, PatKind::Ident(binding_mode, (*path).clone(), None))
+                cx.pat(path.span, PatKind::Ident(binding_mode, *path, None))
             })
             .collect()
     }
diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs
index 7413cef6d32d4..009ab6ac5b12f 100644
--- a/src/librustc_errors/annotate_snippet_emitter_writer.rs
+++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs
@@ -196,7 +196,7 @@ impl AnnotateSnippetEmitterWriter {
     ) {
         let converter = DiagnosticConverter {
             source_map: self.source_map.clone(),
-            level: level.clone(),
+            level: *level,
             message,
             code: code.clone(),
             msp: msp.clone(),
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 588e639f28946..87f39dedd0273 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -236,7 +236,7 @@ fn encode_work_product_index(
     let serialized_products: Vec<_> = work_products
         .iter()
         .map(|(id, work_product)| SerializedWorkProduct {
-            id: id.clone(),
+            id: *id,
             work_product: work_product.clone(),
         })
         .collect();
diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs
index 2b514c301f2a3..42ec8787cb287 100644
--- a/src/librustc_lint/context.rs
+++ b/src/librustc_lint/context.rs
@@ -245,7 +245,7 @@ impl LintStore {
 
     pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
         let target = match self.by_name.get(new_name) {
-            Some(&Id(lint_id)) => lint_id.clone(),
+            Some(&Id(lint_id)) => lint_id,
             _ => bug!("invalid lint renaming of {} to {}", old_name, new_name),
         };
         self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index eb3dcfa72278e..6280121f65566 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -840,7 +840,7 @@ impl<'a, 'tcx> CrateMetadata {
 
     fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
         match self.is_proc_macro(id) {
-            true => self.root.proc_macro_stability.clone(),
+            true => self.root.proc_macro_stability,
             false => self.root.per_def.stability.get(self, id).map(|stab| stab.decode(self)),
         }
     }
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 7f8791d0c34dc..8ad92ce75a851 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -504,7 +504,7 @@ impl<'tcx> EncodeContext<'tcx> {
             },
             proc_macro_data,
             proc_macro_stability: if is_proc_macro {
-                tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone())
+                tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| *stab)
             } else {
                 None
             },
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index f2a44986cc4d4..9d5cf3ec4bec0 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -200,8 +200,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
                 region,
                 reserve_location: location,
                 activation_location: TwoPhaseActivation::NotTwoPhase,
-                borrowed_place: borrowed_place.clone(),
-                assigned_place: assigned_place.clone(),
+                borrowed_place: *borrowed_place,
+                assigned_place: *assigned_place,
             };
             let idx = self.idx_vec.push(borrow);
             self.location_map.insert(location, idx);
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index 6214453e64f78..44ff493b5b4f0 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -65,7 +65,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
         } else if cx.body_owner_kind.is_fn_or_closure() {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
-            let fn_sig = cx.tables().liberated_fn_sigs()[id].clone();
+            let fn_sig = cx.tables().liberated_fn_sigs()[id];
             let fn_def_id = tcx.hir().local_def_id(id);
 
             let ty = tcx.type_of(fn_def_id);
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index af37d218d68f0..5ec7e73f873e0 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -91,7 +91,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 // deprecated_since and its reason.
                 if let Some(parent_stab) = self.parent_stab {
                     if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
-                        stab.rustc_depr = parent_stab.rustc_depr.clone()
+                        stab.rustc_depr = parent_stab.rustc_depr
                     }
                 }
 
diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs
index 4b10b08ddd94c..0b18352df3307 100644
--- a/src/librustc_traits/chalk_context/mod.rs
+++ b/src/librustc_traits/chalk_context/mod.rs
@@ -400,7 +400,7 @@ impl context::UnificationOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
         &mut self,
         value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
     ) -> (Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, UniverseMap) {
-        (value.clone(), UniverseMap)
+        (*value, UniverseMap)
     }
 
     fn invert_goal(
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 6bb7f4995b6ec..084e6c8d083c5 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -175,7 +175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
             ty::FnPtr(sig) => {
-                let expected_sig = ExpectedSig { cause_span: None, sig: sig.skip_binder().clone() };
+                let expected_sig = ExpectedSig { cause_span: None, sig: *sig.skip_binder() };
                 (Some(expected_sig), Some(ty::ClosureKind::Fn))
             }
             _ => (None, None),
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 56013ee3a816f..f37f6921cebaf 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -239,7 +239,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         //  constraint, and add it to our list. Since we make sure to never re-add
         //  deleted items, this process will always finish.
         while !vid_map.is_empty() {
-            let target = vid_map.keys().next().expect("Keys somehow empty").clone();
+            let target = *vid_map.keys().next().expect("Keys somehow empty");
             let deps = vid_map.remove(&target).expect("Entry somehow missing");
 
             for smaller in deps.smaller.iter() {
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 45669d120c7c2..4c4d795824318 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -485,9 +485,7 @@ pub fn run_test(
         }
         StaticBenchFn(benchfn) => {
             // Benchmarks aren't expected to panic, so we run them all in-process.
-            crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
-                (benchfn.clone())(harness)
-            });
+            crate::bench::benchmark(desc, monitor_ch, opts.nocapture, benchfn);
         }
         DynTestFn(f) => {
             match strategy {

From 6246f7e1f90f1b72d5b9b530df2ee81beeb09f20 Mon Sep 17 00:00:00 2001
From: Tyler Mandry <tmandry@gmail.com>
Date: Thu, 16 Jan 2020 16:29:32 -0800
Subject: [PATCH 25/25] Don't propagate __RUST_TEST_INVOKE to subprocess

When -Z panic_abort_tests is enabled, we use an environment variable to
tell the subprocess which test to invoke. If that subprocess then
invokes another Rust test binary, chaos ensues.
---
 src/libtest/lib.rs                      |  3 ++-
 src/test/ui/test-panic-abort.rs         | 11 +++++++++++
 src/test/ui/test-panic-abort.run.stdout |  7 ++++---
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 45669d120c7c2..7782f62d6ed35 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -153,12 +153,13 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
     // If we're being run in SpawnedSecondary mode, run the test here. run_test
     // will then exit the process.
     if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) {
+        env::remove_var(SECONDARY_TEST_INVOKER_VAR);
         let test = tests
             .iter()
             .filter(|test| test.desc.name.as_slice() == name)
             .map(make_owned_test)
             .next()
-            .expect("couldn't find a test with the provided name");
+            .expect(&format!("couldn't find a test with the provided name '{}'", name));
         let TestDescAndFn { desc, testfn } = test;
         let testfn = match testfn {
             StaticTestFn(f) => f,
diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs
index b0679ea1d3df2..b7bf5a150ea8b 100644
--- a/src/test/ui/test-panic-abort.rs
+++ b/src/test/ui/test-panic-abort.rs
@@ -11,6 +11,7 @@
 #![cfg(test)]
 
 use std::io::Write;
+use std::env;
 
 #[test]
 fn it_works() {
@@ -35,3 +36,13 @@ fn it_fails() {
 fn it_exits() {
     std::process::exit(123);
 }
+
+#[test]
+fn no_residual_environment() {
+    for (key, _) in env::vars() {
+        // Look for keys like __RUST_TEST_INVOKE.
+        if key.contains("TEST_INVOKE") {
+            panic!("shouldn't have '{}' in environment", key);
+        }
+    }
+}
diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout
index 46adcfbc2eb4a..2f4bc32ed6a1f 100644
--- a/src/test/ui/test-panic-abort.run.stdout
+++ b/src/test/ui/test-panic-abort.run.stdout
@@ -1,9 +1,10 @@
 
-running 4 tests
+running 5 tests
 test it_exits ... FAILED
 test it_fails ... FAILED
 test it_panics ... ok
 test it_works ... ok
+test no_residual_environment ... ok
 
 failures:
 
@@ -17,7 +18,7 @@ testing123
 testing321
 thread 'main' panicked at 'assertion failed: `(left == right)`
   left: `2`,
- right: `5`', $DIR/test-panic-abort.rs:31:5
+ right: `5`', $DIR/test-panic-abort.rs:32:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
@@ -25,5 +26,5 @@ failures:
     it_exits
     it_fails
 
-test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out