diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 2fad161652f69..f4df6994e047b 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -58,6 +58,7 @@ pub enum DepNode { CoherenceCheckImpl(DefId), CoherenceOverlapCheck(DefId), CoherenceOverlapCheckSpecial(DefId), + CoherenceOverlapInherentCheck(DefId), CoherenceOrphanCheck(DefId), Variance, WfCheck(DefId), diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 1e3546269dbc2..3eca4624bc17d 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -458,14 +458,13 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, } pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - a_is_expected: bool, - origin: TypeOrigin, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>) - -> UnitResult<'tcx> + a_is_expected: bool, + origin: TypeOrigin, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>) + -> UnitResult<'tcx> { - debug!("mk_eq_trait_refs({:?} <: {:?})", - a, b); + debug!("mk_eq_trait_refs({:?} = {:?})", a, b); cx.eq_trait_refs(a_is_expected, origin, a, b) } @@ -476,11 +475,25 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, b: ty::PolyTraitRef<'tcx>) -> UnitResult<'tcx> { - debug!("mk_sub_poly_trait_refs({:?} <: {:?})", - a, b); + debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); cx.sub_poly_trait_refs(a_is_expected, origin, a, b) } +pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, + a_is_expected: bool, + origin: TypeOrigin, + a: &ty::ImplHeader<'tcx>, + b: &ty::ImplHeader<'tcx>) + -> UnitResult<'tcx> +{ + debug!("mk_eq_impl_header({:?} = {:?})", a, b); + match (a.trait_ref, b.trait_ref) { + (Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref), + (None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty), + _ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"), + } +} + fn expected_found(a_is_expected: bool, a: T, b: T) diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index b79849e87ffac..6005d36ff4eb2 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -10,29 +10,25 @@ //! See `README.md` for high-level documentation -use super::Normalized; -use super::SelectionContext; -use super::ObligationCause; -use super::PredicateObligation; -use super::project; -use super::util; +use super::{SelectionContext}; +use super::{Obligation, ObligationCause}; use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; -use middle::subst::{Subst, Substs, TypeSpace}; +use middle::subst::TypeSpace; use middle::ty::{self, Ty, TyCtxt}; use middle::infer::{self, InferCtxt, TypeOrigin}; -use syntax::codemap::{DUMMY_SP, Span}; +use syntax::codemap::DUMMY_SP; #[derive(Copy, Clone)] struct InferIsLocal(bool); -/// If there are types that satisfy both impls, returns a `TraitRef` +/// If there are types that satisfy both impls, returns an `ImplTy` /// with those types substituted (by updating the given `infcx`) pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) - -> Option> + -> Option> { debug!("impl_can_satisfy(\ impl1_def_id={:?}, \ @@ -45,34 +41,28 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>, } /// Can both impl `a` and impl `b` be satisfied by a common type (including -/// `where` clauses)? If so, returns a `TraitRef` that unifies the two impls. +/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls. fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>, a_def_id: DefId, b_def_id: DefId) - -> Option> + -> Option> { debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); - let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, - a_def_id, - util::fresh_type_vars_for_impl); + let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id); + let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id); - let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, - b_def_id, - util::fresh_type_vars_for_impl); - - debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations); - - debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations); + debug!("overlap: a_impl_header={:?}", a_impl_header); + debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(), - true, - TypeOrigin::Misc(DUMMY_SP), - a_trait_ref, - b_trait_ref) { + if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(), + true, + TypeOrigin::Misc(DUMMY_SP), + &a_impl_header, + &b_impl_header) { return None; } @@ -81,9 +71,13 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>, // Are any of the obligations unsatisfiable? If so, no overlap. let infcx = selcx.infcx(); let opt_failing_obligation = - a_obligations.iter() - .chain(&b_obligations) - .map(|o| infcx.resolve_type_vars_if_possible(o)) + a_impl_header.predicates + .iter() + .chain(&b_impl_header.predicates) + .map(|p| infcx.resolve_type_vars_if_possible(p)) + .map(|p| Obligation { cause: ObligationCause::dummy(), + recursion_depth: 0, + predicate: p }) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { @@ -91,7 +85,7 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>, return None } - Some(selcx.infcx().resolve_type_vars_if_possible(&a_trait_ref)) + Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header)) } pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool @@ -125,44 +119,6 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef< orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err() } -type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - impl_def_id: DefId) - -> Substs<'tcx>; - -/// Instantiate fresh variables for all bound parameters of the impl -/// and return the impl trait ref with those variables substituted. -fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - impl_def_id: DefId, - substs_fn: SubstsFn) - -> (ty::TraitRef<'tcx>, - Vec>) -{ - let impl_substs = - &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id); - let impl_trait_ref = - selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); - let impl_trait_ref = - impl_trait_ref.subst(selcx.tcx(), impl_substs); - let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - - let predicates = selcx.tcx().lookup_predicates(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); - let Normalized { value: predicates, obligations: normalization_obligations2 } = - project::normalize(selcx, ObligationCause::dummy(), &predicates); - let impl_obligations = - util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates); - - let impl_obligations: Vec<_> = - impl_obligations.into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); - - (impl_trait_ref, impl_obligations) -} - pub enum OrphanCheckErr<'tcx> { NoLocalInputType, UncoveredTy(Ty<'tcx>), diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 2ecfa119007b8..fbfd4b67b5bd5 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -391,7 +391,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The result is "true" if the obligation *may* hold and "false" if // we can be sure it does not. - /// Evaluates whether the obligation `obligation` can be satisfied (by any means). pub fn evaluate_obligation(&mut self, obligation: &PredicateObligation<'tcx>) diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs index 162ea3a7714df..090d4eeb87437 100644 --- a/src/librustc/middle/ty/fold.rs +++ b/src/librustc/middle/ty/fold.rs @@ -146,6 +146,10 @@ pub trait TypeFolder<'tcx> : Sized { t.super_fold_with(self) } + fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { + imp.super_fold_with(self) + } + fn fold_substs(&mut self, substs: &subst::Substs<'tcx>) -> subst::Substs<'tcx> { diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 2e38080bfb070..b54b0b73ef292 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -152,6 +152,41 @@ impl ImplOrTraitItemContainer { } } +/// The "header" of an impl is everything outside the body: a Self type, a trait +/// ref (in the case of a trait impl), and a set of predicates (from the +/// bounds/where clauses). +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ImplHeader<'tcx> { + pub impl_def_id: DefId, + pub self_ty: Ty<'tcx>, + pub trait_ref: Option>, + pub predicates: Vec>, +} + +impl<'tcx> ImplHeader<'tcx> { + pub fn with_fresh_ty_vars<'a>(selcx: &mut traits::SelectionContext<'a, 'tcx>, + impl_def_id: DefId) + -> ImplHeader<'tcx> + { + let tcx = selcx.tcx(); + let impl_generics = tcx.lookup_item_type(impl_def_id).generics; + let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics); + + let header = ImplHeader { + impl_def_id: impl_def_id, + self_ty: tcx.lookup_item_type(impl_def_id).ty, + trait_ref: tcx.impl_trait_ref(impl_def_id), + predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(), + }.subst(tcx, &impl_substs); + + let traits::Normalized { value: mut header, obligations } = + traits::normalize(selcx, traits::ObligationCause::dummy(), &header); + + header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); + header + } +} + #[derive(Clone)] pub enum ImplOrTraitItem<'tcx> { ConstTraitItem(Rc>), diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 3fe9e02a90d42..57cfdd0d8b8ae 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -446,6 +446,27 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + ty::ImplHeader { + impl_def_id: self.impl_def_id, + self_ty: self.self_ty.fold_with(folder), + trait_ref: self.trait_ref.map(|t| t.fold_with(folder)), + predicates: self.predicates.iter().map(|p| p.fold_with(folder)).collect(), + } + } + + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_impl_header(self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.self_ty.visit_with(visitor) || + self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) || + self.predicates.iter().any(|p| p.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::Region { fn super_fold_with>(&self, _folder: &mut F) -> Self { *self diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index cad321c0b2374..9dc8d7ae943a1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -35,7 +35,9 @@ use CrateCtxt; use middle::infer::{self, InferCtxt, TypeOrigin, new_infer_ctxt}; use std::cell::RefCell; use std::rc::Rc; +use syntax::ast; use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; use util::nodemap::{DefIdMap, FnvHashMap}; use rustc::dep_graph::DepNode; use rustc::front::map as hir_map; @@ -519,6 +521,13 @@ fn enforce_trait_manually_implementable(tcx: &TyCtxt, sp: Span, trait_def_id: De err.emit(); } +// Factored out into helper because the error cannot be defined in multiple locations. +pub fn report_duplicate_item<'tcx>(tcx: &TyCtxt<'tcx>, sp: Span, name: ast::Name) + -> DiagnosticBuilder<'tcx> +{ + struct_span_err!(tcx.sess, sp, E0201, "duplicate definitions with name `{}`:", name) +} + pub fn check_coherence(crate_context: &CrateCtxt) { let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence); let infcx = new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 9ec42b6d3f859..80430076f197d 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -9,7 +9,8 @@ // except according to those terms. //! Overlap: No two impls for the same trait are implemented for the -//! same type. +//! same type. Likewise, no two inherent impls for a given type +//! constructor provide a method with the same name. use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def_id::DefId; @@ -115,7 +116,6 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } } - fn check_if_impls_overlap(&self, impl1_def_id: DefId, impl2_def_id: DefId) @@ -128,8 +128,8 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl2_def_id); let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None); - if let Some(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { - self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref); + if let Some(header) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { + self.report_overlap_error(impl1_def_id, impl2_def_id, header.trait_ref.unwrap()); } } } @@ -150,13 +150,13 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { }).unwrap_or(String::new()) }; - let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, + let mut err = struct_span_err!(self.tcx.sess, self.span_of_def_id(impl1), E0119, "conflicting implementations of trait `{}`{}:", trait_ref, self_type); if impl2.is_local() { - span_note!(&mut err, self.span_of_impl(impl2), + span_note!(&mut err, self.span_of_def_id(impl2), "conflicting implementation is here:"); } else { let cname = self.tcx.sess.cstore.crate_name(impl2.krate); @@ -165,10 +165,61 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { err.emit(); } - fn span_of_impl(&self, impl_did: DefId) -> Span { - let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap(); + fn span_of_def_id(&self, did: DefId) -> Span { + let node_id = self.tcx.map.as_local_node_id(did).unwrap(); self.tcx.map.span(node_id) } + + fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { + #[derive(Copy, Clone, PartialEq)] + enum Namespace { Type, Value } + + fn name_and_namespace(tcx: &TyCtxt, item: &ty::ImplOrTraitItemId) + -> (ast::Name, Namespace) + { + let name = tcx.impl_or_trait_item(item.def_id()).name(); + (name, match *item { + ty::TypeTraitItemId(..) => Namespace::Type, + ty::ConstTraitItemId(..) => Namespace::Value, + ty::MethodTraitItemId(..) => Namespace::Value, + }) + } + + let impl_items = self.tcx.impl_items.borrow(); + + for item1 in &impl_items[&impl1] { + let (name, namespace) = name_and_namespace(&self.tcx, item1); + + for item2 in &impl_items[&impl2] { + if (name, namespace) == name_and_namespace(&self.tcx, item2) { + let mut err = super::report_duplicate_item( + &self.tcx, self.span_of_def_id(item1.def_id()), name); + span_note!(&mut err, self.span_of_def_id(item2.def_id()), + "conflicting definition is here:"); + err.emit(); + } + } + } + } + + fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { + let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); + + let inherent_impls = self.tcx.inherent_impls.borrow(); + let impls = match inherent_impls.get(&ty_def_id) { + Some(impls) => impls, + None => return + }; + + for (i, &impl1_def_id) in impls.iter().enumerate() { + for &impl2_def_id in &impls[(i+1)..] { + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None); + if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) + } + } + } + } } @@ -180,6 +231,11 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { self.check_for_overlapping_impls_of_trait(trait_def_id); } + hir::ItemEnum(..) | hir::ItemStruct(..) => { + let type_def_id = self.tcx.map.local_def_id(item.id); + self.check_for_overlapping_inherent_impls(type_def_id); + } + hir::ItemDefaultImpl(..) => { // look for another default impl; note that due to the // general orphan/coherence rules, it must always be diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3ce03e245785a..b493b64a45fcf 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -63,6 +63,7 @@ use lint; use middle::def::Def; use middle::def_id::DefId; use constrained_type_params as ctp; +use coherence; use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; use middle::const_eval::{self, ConstVal}; @@ -750,17 +751,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { _ => &mut seen_value_items, }; if !seen_items.insert(impl_item.name) { - let desc = match impl_item.node { - hir::ImplItemKind::Const(_, _) => "associated constant", - hir::ImplItemKind::Type(_) => "associated type", - hir::ImplItemKind::Method(ref sig, _) => - match sig.explicit_self.node { - hir::SelfStatic => "associated function", - _ => "method", - }, - }; - - span_err!(tcx.sess, impl_item.span, E0201, "duplicate {}", desc); + coherence::report_duplicate_item(tcx, impl_item.span, impl_item.name).emit(); } if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f376b42fbf968..5c411bec5065d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2285,6 +2285,21 @@ impl Baz for Foo { type Quux = u32; } ``` + +Note, however, that items with the same name are allowed for inherent `impl` +blocks that don't overlap: + +``` +struct Foo(T); + +impl Foo { + fn bar(&self) -> bool { self.0 > 5 } +} + +impl Foo { + fn bar(&self) -> bool { self.0 } +} +``` "##, E0202: r##" diff --git a/src/test/compile-fail/associated-item-duplicate-names-2.rs b/src/test/compile-fail/associated-item-duplicate-names-2.rs index 6a7eaecae7f42..ab903591fbb06 100644 --- a/src/test/compile-fail/associated-item-duplicate-names-2.rs +++ b/src/test/compile-fail/associated-item-duplicate-names-2.rs @@ -14,7 +14,7 @@ struct Foo; impl Foo { const bar: bool = true; - fn bar() {} //~ ERROR duplicate associated function + fn bar() {} //~ ERROR duplicate definitions } fn main() {} diff --git a/src/test/compile-fail/associated-item-duplicate-names-3.rs b/src/test/compile-fail/associated-item-duplicate-names-3.rs index 7c4c5ca6b4eab..12cab13d0b9b3 100644 --- a/src/test/compile-fail/associated-item-duplicate-names-3.rs +++ b/src/test/compile-fail/associated-item-duplicate-names-3.rs @@ -20,7 +20,7 @@ struct Baz; impl Foo for Baz { type Bar = i16; - type Bar = u16; //~ ERROR duplicate associated type + type Bar = u16; //~ ERROR duplicate definitions } fn main() { diff --git a/src/test/compile-fail/associated-item-duplicate-names.rs b/src/test/compile-fail/associated-item-duplicate-names.rs index 4c484b49024ef..85868f5c02085 100644 --- a/src/test/compile-fail/associated-item-duplicate-names.rs +++ b/src/test/compile-fail/associated-item-duplicate-names.rs @@ -19,9 +19,9 @@ trait Foo { impl Foo for () { type Ty = (); - type Ty = usize; //~ ERROR duplicate associated type + type Ty = usize; //~ ERROR duplicate definitions const BAR: u32 = 7; - const BAR: u32 = 8; //~ ERROR duplicate associated constant + const BAR: u32 = 8; //~ ERROR duplicate definitions } fn main() { diff --git a/src/test/compile-fail/impl-duplicate-methods.rs b/src/test/compile-fail/impl-duplicate-methods.rs index 6201d9862bb69..148958ae12897 100644 --- a/src/test/compile-fail/impl-duplicate-methods.rs +++ b/src/test/compile-fail/impl-duplicate-methods.rs @@ -11,7 +11,7 @@ struct Foo; impl Foo { fn orange(&self){} - fn orange(&self){} //~ ERROR duplicate method + fn orange(&self){} //~ ERROR duplicate definitions } fn main() {} diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/compile-fail/inherent-overlap.rs new file mode 100644 index 0000000000000..5b014dbfd2255 --- /dev/null +++ b/src/test/compile-fail/inherent-overlap.rs @@ -0,0 +1,44 @@ +// Copyright 2016 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. + +// Test that you cannot define items with the same name in overlapping inherent +// impl blocks. + +struct Foo; + +impl Foo { + fn id() {} //~ ERROR E0201 +} + +impl Foo { + fn id() {} +} + +struct Bar(T); + +impl Bar { + fn bar(&self) {} //~ ERROR E0201 +} + +impl Bar { + fn bar(&self) {} +} + +struct Baz(T); + +impl Baz { + fn baz(&self) {} //~ ERROR E0201 +} + +impl Baz> { + fn baz(&self) {} +} + +fn main() {} diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs index 328de9f8187e5..62db68dcbb2ee 100644 --- a/src/test/compile-fail/issue-4265.rs +++ b/src/test/compile-fail/issue-4265.rs @@ -17,7 +17,7 @@ impl Foo { Foo { baz: 0 }.bar(); } - fn bar() { //~ ERROR duplicate associated function + fn bar() { //~ ERROR duplicate definitions } } diff --git a/src/test/compile-fail/issue-8153.rs b/src/test/compile-fail/issue-8153.rs index ea7224939ce56..457918b54d4ae 100644 --- a/src/test/compile-fail/issue-8153.rs +++ b/src/test/compile-fail/issue-8153.rs @@ -18,7 +18,7 @@ trait Bar { impl Bar for Foo { fn bar(&self) -> isize {1} - fn bar(&self) -> isize {2} //~ ERROR duplicate method + fn bar(&self) -> isize {2} //~ ERROR duplicate definitions } fn main() { diff --git a/src/test/compile-fail/method-macro-backtrace.rs b/src/test/compile-fail/method-macro-backtrace.rs index 967a8531b2c0a..f3c227849dcbe 100644 --- a/src/test/compile-fail/method-macro-backtrace.rs +++ b/src/test/compile-fail/method-macro-backtrace.rs @@ -29,7 +29,7 @@ impl S { // Cause an error. It shouldn't have any macro backtrace frames. fn bar(&self) { } - fn bar(&self) { } //~ ERROR duplicate method + fn bar(&self) { } //~ ERROR duplicate definitions } fn main() { } diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs index 2343b610ce448..25c97ee2c76a9 100644 --- a/src/test/rustdoc/issue-25001.rs +++ b/src/test/rustdoc/issue-25001.rs @@ -17,15 +17,15 @@ pub trait Bar { fn quux(self); } -impl Foo { +impl Foo { // @has - '//*[@id="method.pass"]//code' 'fn pass()' pub fn pass() {} } -impl Foo { +impl Foo { // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize' pub fn pass() -> usize { 42 } } -impl Foo { +impl Foo { // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize' pub fn pass() -> isize { 42 } }