about summary refs log tree commit diff
diff options
context:
space:
mode:
authorF001 <changchun.fan@qq.com>2018-05-19 00:17:13 +0800
committerF001 <changchun.fan@qq.com>2018-05-20 10:16:33 +0800
commit4bb39966a670864de0078cafc1e5b623ca1b2ec3 (patch)
treecba862b02742a47ae094a4d4f68bf3ebe9c53d06
parent3ea24915894d49cb93eab52e65f1e4f0baa1bc32 (diff)
downloadrust-4bb39966a670864de0078cafc1e5b623ca1b2ec3.tar.gz
rust-4bb39966a670864de0078cafc1e5b623ca1b2ec3.zip
re-implement
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc_typeck/astconv.rs21
-rw-r--r--src/test/ui/lint/issue-50589-multiple-associated-types.rs23
-rw-r--r--src/test/ui/lint/issue-50589-multiple-associated-types.stderr14
4 files changed, 61 insertions, 4 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index ac2fa8515bc..1cb00abbb7e 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -279,6 +279,12 @@ declare_lint! {
     "detects labels that are never used"
 }
 
+declare_lint! {
+    pub DUPLICATE_ASSOCIATED_TYPE_BINDING,
+    Warn,
+    "warns about duplicate associated type bindings in generics"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -330,6 +336,7 @@ impl LintPass for HardwiredLints {
             BARE_TRAIT_OBJECT,
             ABSOLUTE_PATH_NOT_STARTING_WITH_CRATE,
             UNSTABLE_NAME_COLLISION,
+            DUPLICATE_ASSOCIATED_TYPE_BINDING,
         )
     }
 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c1868467503..091ed0a4b36 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -27,7 +27,7 @@ use rustc_target::spec::abi;
 use std::slice;
 use require_c_abi_if_variadic;
 use util::common::ErrorReported;
-use util::nodemap::FxHashSet;
+use util::nodemap::{FxHashSet, FxHashMap};
 use errors::FatalError;
 
 use std::iter;
@@ -398,13 +398,24 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                  trait_ref.path.segments.last().unwrap());
         let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
 
+        let mut dup_bindings = FxHashMap::default();
         poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
             // specify type to assert that error was already reported in Err case:
             let predicate: Result<_, ErrorReported> =
-                self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref,
-                                                                   binding, speculative);
+                self.ast_type_binding_to_poly_projection_predicate(
+                    trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
             predicate.ok() // ok to ignore Err() because ErrorReported (see above)
         }));
+        for (_id, spans) in dup_bindings {
+            if spans.len() > 1 {
+                self.tcx().struct_span_lint_node(
+                        ::rustc::lint::builtin::DUPLICATE_ASSOCIATED_TYPE_BINDING,
+                        trait_ref.ref_id,
+                        spans,
+                        "duplicate associated type binding"
+                    ).emit();
+            }
+        }
 
         debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}",
                trait_ref, poly_projections, poly_trait_ref);
@@ -487,7 +498,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         ref_id: ast::NodeId,
         trait_ref: ty::PolyTraitRef<'tcx>,
         binding: &ConvertedBinding<'tcx>,
-        speculative: bool)
+        speculative: bool,
+        dup_bindings: &mut FxHashMap<DefId, Vec<Span>>)
         -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
@@ -565,6 +577,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             tcx.sess.span_err(binding.span, &msg);
         }
         tcx.check_stability(assoc_ty.def_id, Some(ref_id), binding.span);
+        dup_bindings.entry(assoc_ty.def_id).or_insert(Vec::new()).push(binding.span);
 
         Ok(candidate.map_bound(|trait_ref| {
             ty::ProjectionPredicate {
diff --git a/src/test/ui/lint/issue-50589-multiple-associated-types.rs b/src/test/ui/lint/issue-50589-multiple-associated-types.rs
new file mode 100644
index 00000000000..2c789a139cd
--- /dev/null
+++ b/src/test/ui/lint/issue-50589-multiple-associated-types.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+use std::iter::Iterator;
+
+type Unit = ();
+
+fn test() ->  Box<Iterator<Item = (), Item = Unit>> {
+    Box::new(None.into_iter())
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/lint/issue-50589-multiple-associated-types.stderr b/src/test/ui/lint/issue-50589-multiple-associated-types.stderr
new file mode 100644
index 00000000000..05e02879f1f
--- /dev/null
+++ b/src/test/ui/lint/issue-50589-multiple-associated-types.stderr
@@ -0,0 +1,14 @@
+warning: duplicate associated type binding
+  --> $DIR/issue-50589-multiple-associated-types.rs:17:28
+   |
+LL | fn test() ->  Box<Iterator<Item = (), Item = Unit>> {
+   |                            ^^^^^^^^^  ^^^^^^^^^^^
+   |
+   = note: #[warn(duplicate_associated_type_binding)] on by default
+
+warning: duplicate associated type binding
+  --> $DIR/issue-50589-multiple-associated-types.rs:17:28
+   |
+LL | fn test() ->  Box<Iterator<Item = (), Item = Unit>> {
+   |                            ^^^^^^^^^  ^^^^^^^^^^^
+