]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #43849 - QuietMisdreavus:foreign-impls, r=steveklabnik
authorbors <bors@rust-lang.org>
Wed, 6 Sep 2017 11:24:18 +0000 (11:24 +0000)
committerbors <bors@rust-lang.org>
Wed, 6 Sep 2017 11:24:18 +0000 (11:24 +0000)
rustdoc: add new "Implementations on Foreign Types" section to traits

Demo screenshot:

![image](https://user-images.githubusercontent.com/5217170/29281219-c547f758-80e3-11e7-808f-49f592c65c5b.png)

Full demo available at https://tonberry.quietmisdreavus.net/foreign-test/foreign_test/trait.CheckIt.html

This PR splits the "Implementors" section on trait pages into two: First, for impls on types local to the crate, their impls are kept as-is, printing one line for the impl line, and any additional lines for associated types. However, for types external to the crate, they are now pulled up over the others and are printed (almost) like the summary impl on the type page itself. This gives any doc comments on these impls or methods to be exposed in the documentation.

There's just one small problem, though: [libstd docs apparently surface impls for libc and rand, possibly among others](https://tonberry.quietmisdreavus.net/foreign-std/std/marker/trait.Copy.html#foreign-impls). This adds this section to pages in the std docs where we might not want them to show up in the first place. I think this is a bug distinct from this PR, but it does make it drastically apparent.

~~My question, then, is this: Do we want this here? Taking it out involves fixing which impls are visible to rustdoc, possibly specifically when rendering the std facade. I'm convinced this is fine to land as-is, since it adds a feature specifically for non-std crates (i'm thinking of things like `num` or related crates that implement things on primitives or std types as part of their functionality).~~ (EDIT: I have an open PR to fix this: https://github.com/rust-lang/rust/pull/44026)

13 files changed:
src/librustc/traits/coherence.rs
src/librustc/traits/mod.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/test/compile-fail/coherence-overlap-downstream-inherent.rs [new file with mode: 0644]
src/test/compile-fail/coherence-overlap-downstream.rs [new file with mode: 0644]
src/test/compile-fail/coherence-overlap-issue-23516-inherent.rs [new file with mode: 0644]
src/test/compile-fail/coherence-overlap-issue-23516.rs
src/test/compile-fail/coherence-overlap-upstream-inherent.rs [new file with mode: 0644]
src/test/compile-fail/coherence-overlap-upstream.rs [new file with mode: 0644]
src/test/ui/codemap_tests/overlapping_inherent_impls.stderr

index 431bd8ee88f709883aa72813689aa76cee731c72..f3682f8d35d84d901f32e49132977c1a00075973 100644 (file)
@@ -13,6 +13,7 @@
 use hir::def_id::{DefId, LOCAL_CRATE};
 use syntax_pos::DUMMY_SP;
 use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
+use traits::select::IntercrateAmbiguityCause;
 use ty::{self, Ty, TyCtxt};
 use ty::subst::Subst;
 
 #[derive(Copy, Clone)]
 struct InferIsLocal(bool);
 
+pub struct OverlapResult<'tcx> {
+    pub impl_header: ty::ImplHeader<'tcx>,
+    pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+}
+
 /// If there are types that satisfy both impls, returns a suitably-freshened
 /// `ImplHeader` with those types substituted
 pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
                                           impl1_def_id: DefId,
                                           impl2_def_id: DefId)
-                                          -> Option<ty::ImplHeader<'tcx>>
+                                          -> Option<OverlapResult<'tcx>>
 {
     debug!("impl_can_satisfy(\
            impl1_def_id={:?}, \
@@ -65,7 +71,7 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
 fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
                             a_def_id: DefId,
                             b_def_id: DefId)
-                            -> Option<ty::ImplHeader<'tcx>>
+                            -> Option<OverlapResult<'tcx>>
 {
     debug!("overlap(a_def_id={:?}, b_def_id={:?})",
            a_def_id,
@@ -113,11 +119,14 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
         return None
     }
 
-    Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
+    Some(OverlapResult {
+        impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
+        intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
+    })
 }
 
 pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                             trait_ref: &ty::TraitRef<'tcx>) -> bool
+                                             trait_ref: ty::TraitRef<'tcx>) -> bool
 {
     debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
 
@@ -131,10 +140,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     // if the trait is not marked fundamental, then it's always possible that
     // an ancestor crate will impl this in the future, if they haven't
     // already
-    if
-        trait_ref.def_id.krate != LOCAL_CRATE &&
-        !tcx.has_attr(trait_ref.def_id, "fundamental")
-    {
+    if !trait_ref_is_local_or_fundamental(tcx, trait_ref) {
         debug!("trait_ref_is_knowable: trait is neither local nor fundamental");
         return false;
     }
@@ -148,6 +154,12 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
 }
 
+pub fn trait_ref_is_local_or_fundamental<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                                         trait_ref: ty::TraitRef<'tcx>)
+                                                         -> bool {
+    trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, "fundamental")
+}
+
 pub enum OrphanCheckErr<'tcx> {
     NoLocalInputType,
     UncoveredTy(Ty<'tcx>),
@@ -177,11 +189,11 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         return Ok(());
     }
 
-    orphan_check_trait_ref(tcx, &trait_ref, InferIsLocal(false))
+    orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false))
 }
 
 fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
-                                trait_ref: &ty::TraitRef<'tcx>,
+                                trait_ref: ty::TraitRef<'tcx>,
                                 infer_is_local: InferIsLocal)
                                 -> Result<(), OrphanCheckErr<'tcx>>
 {
index 33dcf3c76e6cfcb885af7ffc6c35f2490d5dd113..22c92776c5e4e01a9516a1bdfb2c6fd592abfa07 100644 (file)
@@ -28,9 +28,7 @@
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
-pub use self::coherence::orphan_check;
-pub use self::coherence::overlapping_impls;
-pub use self::coherence::OrphanCheckErr;
+pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult};
 pub use self::fulfill::{FulfillmentContext, RegionObligation};
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{normalize, normalize_projection_type, Normalized};
@@ -39,6 +37,7 @@
 pub use self::object_safety::MethodViolationCode;
 pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
 pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
+pub use self::select::IntercrateAmbiguityCause;
 pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
 pub use self::specialize::{SpecializesCache, find_associated_item};
 pub use self::util::elaborate_predicates;
index 726e5d83428ca0807d0281b1e6aa3128d0c803fe..cd259fc2528e5d3143574a2d733a50c5875db552 100644 (file)
@@ -90,6 +90,45 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     intercrate: bool,
 
     inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
+
+    intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+}
+
+#[derive(Clone)]
+pub enum IntercrateAmbiguityCause {
+    DownstreamCrate {
+        trait_desc: String,
+        self_desc: Option<String>,
+    },
+    UpstreamCrateUpdate {
+        trait_desc: String,
+        self_desc: Option<String>,
+    },
+}
+
+impl IntercrateAmbiguityCause {
+    /// Emits notes when the overlap is caused by complex intercrate ambiguities.
+    /// See #23980 for details.
+    pub fn add_intercrate_ambiguity_hint<'a, 'tcx>(&self,
+                                                   err: &mut ::errors::DiagnosticBuilder) {
+        match self {
+            &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
+                let self_desc = if let &Some(ref ty) = self_desc {
+                    format!(" for type `{}`", ty)
+                } else { "".to_string() };
+                err.note(&format!("downstream crates may implement trait `{}`{}",
+                                  trait_desc, self_desc));
+            }
+            &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
+                let self_desc = if let &Some(ref ty) = self_desc {
+                    format!(" for type `{}`", ty)
+                } else { "".to_string() };
+                err.note(&format!("upstream crates may add new impl of trait `{}`{} \
+                                  in future versions",
+                                  trait_desc, self_desc));
+            }
+        }
+    }
 }
 
 // A stack that walks back up the stack frame.
@@ -380,6 +419,7 @@ pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx
             freshener: infcx.freshener(),
             intercrate: false,
             inferred_obligations: SnapshotVec::new(),
+            intercrate_ambiguity_causes: Vec::new(),
         }
     }
 
@@ -389,6 +429,7 @@ pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'c
             freshener: infcx.freshener(),
             intercrate: true,
             inferred_obligations: SnapshotVec::new(),
+            intercrate_ambiguity_causes: Vec::new(),
         }
     }
 
@@ -404,6 +445,10 @@ pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
 
+    pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
+        &self.intercrate_ambiguity_causes
+    }
+
     /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
     /// context's self.
     fn in_snapshot<R, F>(&mut self, f: F) -> R
@@ -757,6 +802,22 @@ fn evaluate_stack<'o>(&mut self,
         if unbound_input_types && self.intercrate {
             debug!("evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
                    stack.fresh_trait_ref);
+            // Heuristics: show the diagnostics when there are no candidates in crate.
+            if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                    let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                    let self_ty = trait_ref.self_ty();
+                    let cause = IntercrateAmbiguityCause::DownstreamCrate {
+                        trait_desc: trait_ref.to_string(),
+                        self_desc: if self_ty.has_concrete_skeleton() {
+                            Some(self_ty.to_string())
+                        } else {
+                            None
+                        },
+                    };
+                    self.intercrate_ambiguity_causes.push(cause);
+                }
+            }
             return EvaluatedToAmbig;
         }
         if unbound_input_types &&
@@ -1003,6 +1064,25 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
 
         if !self.is_knowable(stack) {
             debug!("coherence stage: not knowable");
+            // Heuristics: show the diagnostics when there are no candidates in crate.
+            let candidate_set = self.assemble_candidates(stack)?;
+            if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                let self_ty = trait_ref.self_ty();
+                let trait_desc = trait_ref.to_string();
+                let self_desc = if self_ty.has_concrete_skeleton() {
+                    Some(self_ty.to_string())
+                } else {
+                    None
+                };
+                let cause = if !coherence::trait_ref_is_local_or_fundamental(self.tcx(),
+                                                                             trait_ref) {
+                    IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+                } else {
+                    IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+                };
+                self.intercrate_ambiguity_causes.push(cause);
+            }
             return Ok(None);
         }
 
@@ -1124,7 +1204,7 @@ fn is_knowable<'o>(&mut self,
         // ok to skip binder because of the nature of the
         // trait-ref-is-knowable check, which does not care about
         // bound regions
-        let trait_ref = &predicate.skip_binder().trait_ref;
+        let trait_ref = predicate.skip_binder().trait_ref;
 
         coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
     }
index 2dd6ca4b5a92853964c67d81921b0178f2ef920d..f9332fc6697e02bff8cc67f6fcf98b8167d9883c 100644 (file)
@@ -25,6 +25,7 @@
 use infer::{InferCtxt, InferOk};
 use ty::subst::{Subst, Substs};
 use traits::{self, Reveal, ObligationCause};
+use traits::select::IntercrateAmbiguityCause;
 use ty::{self, TyCtxt, TypeFoldable};
 use syntax_pos::DUMMY_SP;
 use std::rc::Rc;
@@ -36,6 +37,7 @@ pub struct OverlapError {
     pub with_impl: DefId,
     pub trait_desc: String,
     pub self_desc: Option<String>,
+    pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
 }
 
 /// Given a subst for the requested impl, translate it to a subst
@@ -337,6 +339,10 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                     }
                 }
 
+                for cause in &overlap.intercrate_ambiguity_causes {
+                    cause.add_intercrate_ambiguity_hint(&mut err);
+                }
+
                 err.emit();
             }
         } else {
index 5242accceabb3418d3f9b11746861c8a4604de23..2640542ad10593366fd782c176dae7ed1eb04504 100644 (file)
@@ -113,7 +113,7 @@ fn insert(&mut self,
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
-                if let Some(impl_header) = overlap {
+                if let Some(overlap) = overlap {
                     if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                         return Ok((false, false));
                     }
@@ -123,7 +123,7 @@ fn insert(&mut self,
 
                     if le == ge {
                         // overlap, but no specialization; error out
-                        let trait_ref = impl_header.trait_ref.unwrap();
+                        let trait_ref = overlap.impl_header.trait_ref.unwrap();
                         let self_ty = trait_ref.self_ty();
                         Err(OverlapError {
                             with_impl: possible_sibling,
@@ -135,7 +135,8 @@ fn insert(&mut self,
                                 Some(self_ty.to_string())
                             } else {
                                 None
-                            }
+                            },
+                            intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
                         })
                     } else {
                         Ok((le, ge))
index 078ae34bc524c41cc9830964b1a35955d52d6aff..76dcfe36e4fcdc80e8d07763964cda2ffc575a2e 100644 (file)
@@ -26,7 +26,8 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
-    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
+                                       overlap: traits::OverlapResult) {
         #[derive(Copy, Clone, PartialEq)]
         enum Namespace {
             Type,
@@ -50,16 +51,22 @@ enum Namespace {
 
             for &item2 in &impl_items2[..] {
                 if (name, namespace) == name_and_namespace(item2) {
-                    struct_span_err!(self.tcx.sess,
-                                     self.tcx.span_of_impl(item1).unwrap(),
-                                     E0592,
-                                     "duplicate definitions with name `{}`",
-                                     name)
-                        .span_label(self.tcx.span_of_impl(item1).unwrap(),
-                                    format!("duplicate definitions for `{}`", name))
-                        .span_label(self.tcx.span_of_impl(item2).unwrap(),
-                                    format!("other definition for `{}`", name))
-                        .emit();
+                    let mut err = struct_span_err!(self.tcx.sess,
+                                                   self.tcx.span_of_impl(item1).unwrap(),
+                                                   E0592,
+                                                   "duplicate definitions with name `{}`",
+                                                   name);
+
+                    err.span_label(self.tcx.span_of_impl(item1).unwrap(),
+                                   format!("duplicate definitions for `{}`", name));
+                    err.span_label(self.tcx.span_of_impl(item2).unwrap(),
+                                   format!("other definition for `{}`", name));
+
+                    for cause in &overlap.intercrate_ambiguity_causes {
+                        cause.add_intercrate_ambiguity_hint(&mut err);
+                    }
+
+                    err.emit();
                 }
             }
         }
@@ -71,8 +78,9 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
                 self.tcx.infer_ctxt().enter(|infcx| {
-                    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)
+                    if let Some(overlap) =
+                            traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
+                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap)
                     }
                 });
             }
diff --git a/src/test/compile-fail/coherence-overlap-downstream-inherent.rs b/src/test/compile-fail/coherence-overlap-downstream-inherent.rs
new file mode 100644 (file)
index 0000000..66068b5
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2017 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.
+
+// Tests that we consider `T: Sugar + Fruit` to be ambiguous, even
+// though no impls are found.
+
+struct Sweet<X>(X);
+pub trait Sugar {}
+pub trait Fruit {}
+impl<T:Sugar> Sweet<T> { fn dummy(&self) { } }
+//~^ ERROR E0592
+//~| NOTE duplicate definitions for `dummy`
+impl<T:Fruit> Sweet<T> { fn dummy(&self) { } }
+//~^ NOTE other definition for `dummy`
+
+trait Bar<X> {}
+struct A<T, X>(T, X);
+impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} }
+//~^ ERROR E0592
+//~| NOTE duplicate definitions for `f`
+//~| NOTE downstream crates may implement trait `Bar<_>` for type `i32`
+impl<X> A<i32, X> { fn f(&self) {} }
+//~^ NOTE other definition for `f`
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-overlap-downstream.rs b/src/test/compile-fail/coherence-overlap-downstream.rs
new file mode 100644 (file)
index 0000000..1df0273
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2017 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.
+
+// Tests that we consider `T: Sugar + Fruit` to be ambiguous, even
+// though no impls are found.
+
+pub trait Sugar {}
+pub trait Fruit {}
+pub trait Sweet {}
+impl<T:Sugar> Sweet for T { }
+//~^ NOTE first implementation here
+impl<T:Fruit> Sweet for T { }
+//~^ ERROR E0119
+//~| NOTE conflicting implementation
+
+pub trait Foo<X> {}
+pub trait Bar<X> {}
+impl<X, T> Foo<X> for T where T: Bar<X> {}
+//~^ NOTE first implementation here
+impl<X> Foo<X> for i32 {}
+//~^ ERROR E0119
+//~| NOTE conflicting implementation for `i32`
+//~| NOTE downstream crates may implement trait `Bar<_>` for type `i32`
+
+fn main() { }
diff --git a/src/test/compile-fail/coherence-overlap-issue-23516-inherent.rs b/src/test/compile-fail/coherence-overlap-issue-23516-inherent.rs
new file mode 100644 (file)
index 0000000..355af60
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2015 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.
+
+// Tests that we consider `Box<U>: !Sugar` to be ambiguous, even
+// though we see no impl of `Sugar` for `Box`. Therefore, an overlap
+// error is reported for the following pair of impls (#23516).
+
+pub trait Sugar {}
+
+struct Cake<X>(X);
+
+impl<T:Sugar> Cake<T> { fn dummy(&self) { } }
+//~^ ERROR E0592
+//~| NOTE duplicate definitions for `dummy`
+//~| NOTE downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>`
+impl<U:Sugar> Cake<Box<U>> { fn dummy(&self) { } }
+//~^ NOTE other definition for `dummy`
+
+fn main() { }
index 51d7c3e8b4cb17962f0809276d5abf49b84a85af..ffef5bf10871a09b33c4db27a16e492159a0c794 100644 (file)
 pub trait Sugar { fn dummy(&self) { } }
 pub trait Sweet { fn dummy(&self) { } }
 impl<T:Sugar> Sweet for T { }
-impl<U:Sugar> Sweet for Box<U> { } //~ ERROR E0119
+//~^ NOTE first implementation here
+impl<U:Sugar> Sweet for Box<U> { }
+//~^ ERROR E0119
+//~| NOTE conflicting implementation for `std::boxed::Box<_>`
+//~| NOTE downstream crates may implement trait `Sugar` for type `std::boxed::Box<_>`
+
 fn main() { }
diff --git a/src/test/compile-fail/coherence-overlap-upstream-inherent.rs b/src/test/compile-fail/coherence-overlap-upstream-inherent.rs
new file mode 100644 (file)
index 0000000..1d0c631
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+// Tests that we consider `i16: Remote` to be ambiguous, even
+// though the upstream crate doesn't implement it for now.
+
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib;
+
+use coherence_lib::Remote;
+
+struct A<X>(X);
+impl<T> A<T> where T: Remote { fn dummy(&self) { } }
+//~^ ERROR E0592
+//~| NOTE duplicate definitions for `dummy`
+//~| NOTE upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16`
+impl A<i16> { fn dummy(&self) { } }
+//~^ NOTE other definition for `dummy`
+
+fn main() {}
diff --git a/src/test/compile-fail/coherence-overlap-upstream.rs b/src/test/compile-fail/coherence-overlap-upstream.rs
new file mode 100644 (file)
index 0000000..e978143
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+// Tests that we consider `i16: Remote` to be ambiguous, even
+// though the upstream crate doesn't implement it for now.
+
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib;
+
+use coherence_lib::Remote;
+
+trait Foo {}
+impl<T> Foo for T where T: Remote {}
+//~^ NOTE first implementation here
+impl Foo for i16 {}
+//~^ ERROR E0119
+//~| NOTE conflicting implementation for `i16`
+//~| NOTE upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16`
+
+fn main() {}
index de8a24cf33f44c12f0e70d3dbf57e99101a67e09..eaf42cde22f762c44a64688bbadbce5f3302c97e 100644 (file)
@@ -24,6 +24,8 @@ error[E0592]: duplicate definitions with name `baz`
 ...
 43 |     fn baz(&self) {}
    |     ---------------- other definition for `baz`
+   |
+   = note: upstream crates may add new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions
 
 error: aborting due to 3 previous errors