diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ac2fa8515bc1d..5d7d2f0f9e698 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_BINDINGS, + 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_BINDINGS, ) } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index cfd5cf5a0f98c..e35537459b70f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -283,6 +283,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue TBD", edition: Some(Edition::Edition2018), }, + FutureIncompatibleInfo { + id: LintId::of(DUPLICATE_ASSOCIATED_TYPE_BINDINGS), + reference: "issue #50589 ", + edition: None, + }, ]); // Register renamed and removed lints diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f2fe8b1d891d9..68587fb8b3c1e 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,11 +398,12 @@ 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) })); @@ -487,7 +488,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) -> Result, ErrorReported> { let tcx = self.tcx(); @@ -566,6 +568,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } tcx.check_stability(assoc_ty.def_id, Some(ref_id), binding.span); + if !speculative { + dup_bindings.entry(assoc_ty.def_id) + .and_modify(|prev_span| { + let mut err = self.tcx().struct_span_lint_node( + ::rustc::lint::builtin::DUPLICATE_ASSOCIATED_TYPE_BINDINGS, + ref_id, + binding.span, + &format!("associated type binding `{}` specified more than once", + binding.item_name) + ); + err.span_label(binding.span, "used more than once"); + err.span_label(*prev_span, format!("first use of `{}`", binding.item_name)); + err.emit(); + }) + .or_insert(binding.span); + } + Ok(candidate.map_bound(|trait_ref| { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy::from_ref_and_name( 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 0000000000000..2c789a139cd3a --- /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 or the MIT license +// , 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> { + 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 0000000000000..7f0a1ee1f3307 --- /dev/null +++ b/src/test/ui/lint/issue-50589-multiple-associated-types.stderr @@ -0,0 +1,23 @@ +warning: associated type binding `Item` specified more than once + --> $DIR/issue-50589-multiple-associated-types.rs:17:39 + | +LL | fn test() -> Box> { + | --------- ^^^^^^^^^^^ used more than once + | | + | first use of `Item` + | + = note: #[warn(duplicate_associated_type_bindings)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #50589 + +warning: associated type binding `Item` specified more than once + --> $DIR/issue-50589-multiple-associated-types.rs:17:39 + | +LL | fn test() -> Box> { + | --------- ^^^^^^^^^^^ used more than once + | | + | first use of `Item` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #50589 +