Skip to content

Commit bc33dd7

Browse files
committed
Provide overlapping types for coherence errors
Currently, a coherence error based on overlapping impls simply mentions the trait, and points to the two conflicting impls: ``` error: conflicting implementations for trait `Foo` ``` With this commit, the error will include all input types to the trait (including the `Self` type) after unification between the overlapping impls. In other words, the error message will provide feedback with full type details, like: ``` error: conflicting implementations of trait `Foo<u32>` for type `u8`: ``` When the `Self` type for the two impls unify to an inference variable, it is elided in the output, since "for type `_`" is just noise in that case. Closes #23980
1 parent ed121aa commit bc33dd7

File tree

7 files changed

+95
-50
lines changed

7 files changed

+95
-50
lines changed

src/librustc/middle/traits/coherence.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ use syntax::codemap::{DUMMY_SP, Span};
2727
#[derive(Copy, Clone)]
2828
struct InferIsLocal(bool);
2929

30-
/// True if there exist types that satisfy both of the two given impls.
31-
pub fn overlapping_impls(infcx: &InferCtxt,
32-
impl1_def_id: DefId,
33-
impl2_def_id: DefId)
34-
-> bool
30+
/// If there are types that satisfy both impls, returns a `TraitRef`
31+
/// with those types substituted (by updating the given `infcx`)
32+
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
33+
impl1_def_id: DefId,
34+
impl2_def_id: DefId)
35+
-> Option<ty::TraitRef<'tcx>>
3536
{
3637
debug!("impl_can_satisfy(\
3738
impl1_def_id={:?}, \
@@ -40,16 +41,15 @@ pub fn overlapping_impls(infcx: &InferCtxt,
4041
impl2_def_id);
4142

4243
let selcx = &mut SelectionContext::intercrate(infcx);
43-
infcx.probe(|_| {
44-
overlap(selcx, impl1_def_id, impl2_def_id)
45-
})
44+
overlap(selcx, impl1_def_id, impl2_def_id)
4645
}
4746

48-
/// Can both impl `a` and impl `b` be satisfied by a common type (including `where` clauses)?
49-
fn overlap(selcx: &mut SelectionContext,
50-
a_def_id: DefId,
51-
b_def_id: DefId)
52-
-> bool
47+
/// Can both impl `a` and impl `b` be satisfied by a common type (including
48+
/// `where` clauses)? If so, returns a `TraitRef` that unifies the two impls.
49+
fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
50+
a_def_id: DefId,
51+
b_def_id: DefId)
52+
-> Option<ty::TraitRef<'tcx>>
5353
{
5454
debug!("overlap(a_def_id={:?}, b_def_id={:?})",
5555
a_def_id,
@@ -73,7 +73,7 @@ fn overlap(selcx: &mut SelectionContext,
7373
TypeOrigin::Misc(DUMMY_SP),
7474
a_trait_ref,
7575
b_trait_ref) {
76-
return false;
76+
return None;
7777
}
7878

7979
debug!("overlap: unification check succeeded");
@@ -88,10 +88,10 @@ fn overlap(selcx: &mut SelectionContext,
8888

8989
if let Some(failing_obligation) = opt_failing_obligation {
9090
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
91-
return false
91+
return None
9292
}
9393

94-
true
94+
Some(selcx.infcx().resolve_type_vars_if_possible(&a_trait_ref))
9595
}
9696

9797
pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool

src/librustc_typeck/coherence/overlap.rs

+28-25
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,19 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
6565
// borrows are safe.
6666
let blanket_impls = trait_def.blanket_impls.borrow();
6767
let nonblanket_impls = trait_def.nonblanket_impls.borrow();
68-
let trait_def_id = trait_def.trait_ref.def_id;
6968

7069
// Conflicts can only occur between a blanket impl and another impl,
7170
// or between 2 non-blanket impls of the same kind.
7271

7372
for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
7473
for &impl2_def_id in &blanket_impls[(i+1)..] {
75-
self.check_if_impls_overlap(trait_def_id,
76-
impl1_def_id,
74+
self.check_if_impls_overlap(impl1_def_id,
7775
impl2_def_id);
7876
}
7977

8078
for v in nonblanket_impls.values() {
8179
for &impl2_def_id in v {
82-
self.check_if_impls_overlap(trait_def_id,
83-
impl1_def_id,
80+
self.check_if_impls_overlap(impl1_def_id,
8481
impl2_def_id);
8582
}
8683
}
@@ -89,8 +86,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
8986
for impl_group in nonblanket_impls.values() {
9087
for (i, &impl1_def_id) in impl_group.iter().enumerate() {
9188
for &impl2_def_id in &impl_group[(i+1)..] {
92-
self.check_if_impls_overlap(trait_def_id,
93-
impl1_def_id,
89+
self.check_if_impls_overlap(impl1_def_id,
9490
impl2_def_id);
9591
}
9692
}
@@ -121,40 +117,47 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
121117

122118

123119
fn check_if_impls_overlap(&self,
124-
trait_def_id: DefId,
125120
impl1_def_id: DefId,
126121
impl2_def_id: DefId)
127122
{
128123
if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
129124
impl1_def_id, impl2_def_id)
130125
{
131-
debug!("check_if_impls_overlap({:?}, {:?}, {:?})",
132-
trait_def_id,
126+
debug!("check_if_impls_overlap({:?}, {:?})",
133127
impl1_def_id,
134128
impl2_def_id);
135129

136130
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
137-
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
138-
self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id);
131+
if let Some(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
132+
self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref);
139133
}
140134
}
141135
}
142136

143-
fn report_overlap_error(&self, trait_def_id: DefId,
144-
impl1: DefId, impl2: DefId) {
137+
fn report_overlap_error(&self,
138+
impl1: DefId,
139+
impl2: DefId,
140+
trait_ref: ty::TraitRef)
141+
{
142+
// only print the Self type if it's concrete; otherwise, it's not adding much information.
143+
let self_type = {
144+
trait_ref.substs.self_ty().and_then(|ty| {
145+
if let ty::TyInfer(_) = ty.sty {
146+
None
147+
} else {
148+
Some(format!(" for type `{}`", ty))
149+
}
150+
}).unwrap_or(String::new())
151+
};
145152

146153
span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
147-
"conflicting implementations for trait `{}`",
148-
self.tcx.item_path_str(trait_def_id));
149-
150-
self.report_overlap_note(impl2);
151-
}
152-
153-
fn report_overlap_note(&self, impl2: DefId) {
154+
"conflicting implementations of trait `{}`{}:",
155+
trait_ref,
156+
self_type);
154157

155158
if impl2.is_local() {
156159
span_note!(self.tcx.sess, self.span_of_impl(impl2),
157-
"note conflicting implementation here");
160+
"conflicting implementation is here:");
158161
} else {
159162
let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
160163
self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", cname));
@@ -180,9 +183,9 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
180183
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
181184
match prev_default_impl {
182185
Some(prev_id) => {
183-
self.report_overlap_error(trait_ref.def_id,
184-
impl_def_id,
185-
self.tcx.map.local_def_id(prev_id));
186+
self.report_overlap_error(impl_def_id,
187+
self.tcx.map.local_def_id(prev_id),
188+
trait_ref);
186189
}
187190
None => { }
188191
}

src/librustc_typeck/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1569,8 +1569,8 @@ struct Foo {
15691569
value: usize
15701570
}
15711571
1572-
impl MyTrait for Foo { // error: conflicting implementations for trait
1573-
// `MyTrait`
1572+
impl MyTrait for Foo { // error: conflicting implementations of trait
1573+
// `MyTrait` for type `Foo`
15741574
fn get(&self) -> usize { self.value }
15751575
}
15761576
```

src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ trait MyTrait {}
1515
struct TestType<T>(::std::marker::PhantomData<T>);
1616

1717
unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
18-
//~^ ERROR conflicting implementations for trait `core::marker::Send`
19-
//~^^ ERROR conflicting implementations for trait `core::marker::Send`
18+
//~^ ERROR conflicting implementations of trait `core::marker::Send`
19+
//~^^ ERROR conflicting implementations of trait `core::marker::Send`
2020

2121
impl<T: MyTrait> !Send for TestType<T> {}
22-
//~^ ERROR conflicting implementations for trait `core::marker::Send`
22+
//~^ ERROR conflicting implementations of trait `core::marker::Send`
2323

2424
unsafe impl<T:'static> Send for TestType<T> {}
25-
//~^ ERROR error: conflicting implementations for trait `core::marker::Send`
25+
//~^ ERROR error: conflicting implementations of trait `core::marker::Send`
2626

2727
impl !Send for TestType<i32> {}
2828

src/test/compile-fail/coherence-default-trait-impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ trait MyTrait {}
1515
impl MyTrait for .. {}
1616

1717
impl MyTrait for .. {}
18-
//~^ ERROR conflicting implementations for trait `MyTrait`
18+
//~^ ERROR conflicting implementations of trait `MyTrait`
1919

2020
trait MySafeTrait {}
2121

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Foo {}
12+
13+
impl<T> Foo for T {} //~ ERROR conflicting implementations of trait `Foo`:
14+
impl<U> Foo for U {}
15+
16+
trait Bar {}
17+
18+
impl<T> Bar for T {} //~ ERROR conflicting implementations of trait `Bar` for type `u8`:
19+
impl Bar for u8 {}
20+
21+
trait Baz<T> {}
22+
23+
impl<T, U> Baz<U> for T {} //~ ERROR conflicting implementations of trait `Baz<_>` for type `u8`:
24+
impl<T> Baz<T> for u8 {}
25+
26+
trait Quux<T> {}
27+
28+
impl<T, U> Quux<U> for T {} //~ ERROR conflicting implementations of trait `Quux<_>`:
29+
impl<T> Quux<T> for T {}
30+
31+
trait Qaar<T> {}
32+
33+
impl<T, U> Qaar<U> for T {} //~ ERROR conflicting implementations of trait `Qaar<u8>`:
34+
impl<T> Qaar<u8> for T {}
35+
36+
trait Qaax<T> {}
37+
38+
impl<T, U> Qaax<U> for T {}
39+
//~^ ERROR conflicting implementations of trait `Qaax<u8>` for type `u32`:
40+
impl Qaax<u8> for u32 {}
41+
42+
fn main() {}

src/test/compile-fail/issue-28568.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
struct MyStruct;
1212

1313
impl Drop for MyStruct {
14-
//~^ ERROR conflicting implementations for trait
14+
//~^ ERROR conflicting implementations of trait
1515
fn drop(&mut self) { }
1616
}
1717

1818
impl Drop for MyStruct {
19-
//~^ NOTE conflicting implementation here
19+
//~^ NOTE conflicting implementation is here
2020
fn drop(&mut self) { }
2121
}
2222

0 commit comments

Comments
 (0)