From 69f0cee85dab86b8a27321cfce45adcb1f549d0c Mon Sep 17 00:00:00 2001
From: William Lee <wlee@mochify.com>
Date: Tue, 30 Aug 2016 17:30:08 -0400
Subject: [PATCH] Bonus fix for #35280. Part of #35233. Fixes #36057. Adding
 expanded notes/context for what trait a parameter shadows as part of E0194
 error messages.

---
 src/librustc_typeck/check/wfcheck.rs | 28 ++++++++++++++++++++++------
 src/test/compile-fail/E0194.rs       |  4 ++--
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index a236c8baa9f9c..435442bd30a65 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -16,7 +16,7 @@ use middle::region::{CodeExtent};
 use rustc::infer::TypeOrigin;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::nodemap::FnvHashSet;
+use rustc::util::nodemap::{FnvHashSet, FnvHashMap};
 
 use syntax::ast;
 use syntax_pos::Span;
@@ -519,11 +519,26 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
 fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) {
     let parent = tcx.lookup_generics(generics.parent.unwrap());
-    let impl_params: FnvHashSet<_> = parent.types.iter().map(|tp| tp.name).collect();
+    let impl_params: FnvHashMap<_, _> = parent.types
+                                        .iter()
+                                        .map(|tp| (tp.name, tp.def_id))
+                                        .collect();
 
     for method_param in &generics.types {
-        if impl_params.contains(&method_param.name) {
-            error_194(tcx, span, method_param.name);
+        if impl_params.contains_key(&method_param.name) {
+            // Tighten up the span to focus on only the shadowing type
+            let shadow_node_id = tcx.map.as_local_node_id(method_param.def_id).unwrap();
+            let type_span = match tcx.map.opt_span(shadow_node_id) {
+                Some(osp) => osp,
+                None => span
+            };
+
+            // The expectation here is that the original trait declaration is
+            // local so it should be okay to just unwrap everything.
+            let trait_def_id = impl_params.get(&method_param.name).unwrap();
+            let trait_node_id = tcx.map.as_local_node_id(*trait_def_id).unwrap();
+            let trait_decl_span = tcx.map.opt_span(trait_node_id).unwrap();
+            error_194(tcx, type_span, trait_decl_span, method_param.name);
         }
     }
 }
@@ -630,10 +645,11 @@ fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::N
     err
 }
 
-fn error_194(tcx: TyCtxt, span: Span, name: ast::Name) {
+fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) {
     struct_span_err!(tcx.sess, span, E0194,
               "type parameter `{}` shadows another type parameter of the same name",
               name)
-        .span_label(span, &format!("`{}` shadows another type parameter", name))
+        .span_label(span, &format!("shadows another type parameter"))
+        .span_label(trait_decl_span, &format!("first `{}` declared here", name))
         .emit();
 }
diff --git a/src/test/compile-fail/E0194.rs b/src/test/compile-fail/E0194.rs
index fa94c88328a86..6b1f718dd76c5 100644
--- a/src/test/compile-fail/E0194.rs
+++ b/src/test/compile-fail/E0194.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-trait Foo<T> {
+trait Foo<T> { //~ NOTE first `T` declared here
     fn do_something(&self) -> T;
     fn do_something_else<T: Clone>(&self, bar: T);
     //~^ ERROR E0194
-    //~| NOTE `T` shadows another type parameter
+    //~| NOTE shadows another type parameter
 }
 
 fn main() {