Skip to content

Commit 6e61bba

Browse files
committed
Auto merge of #45455 - kennytm:print-extern-impl-for-e0119, r=nikomatsakis
Improve diagnostic of E0119 with extern crate, try to print the conflicting impl. Closes #27403. Closes #23563. Should improve #23980. The diagnostic now looks like: ``` error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`: --> $DIR/issue-27403.rs:15:1 | 15 | / impl<S> Into<S> for GenX<S> { 16 | | fn into(self) -> S { 17 | | self.inner 18 | | } 19 | | } | |_^ | = note: conflicting implementation in crate `core`: - impl<T, U> std::convert::Into<U> for T where U: std::convert::From<T>; error: aborting due to previous error ```
2 parents aa40292 + 9d05006 commit 6e61bba

16 files changed

+428
-2
lines changed

src/librustc/traits/specialize/mod.rs

+60-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
use super::{SelectionContext, FulfillmentContext};
2121
use super::util::impl_trait_ref_and_oblig;
2222

23-
use rustc_data_structures::fx::FxHashMap;
23+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2424
use hir::def_id::DefId;
2525
use infer::{InferCtxt, InferOk};
2626
use ty::subst::{Subst, Substs};
@@ -335,7 +335,12 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
335335
|ty| format!(" for `{}`", ty))));
336336
}
337337
Err(cname) => {
338-
err.note(&format!("conflicting implementation in crate `{}`", cname));
338+
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
339+
Some(s) => format!(
340+
"conflicting implementation in crate `{}`:\n- {}", cname, s),
341+
None => format!("conflicting implementation in crate `{}`", cname),
342+
};
343+
err.note(&msg);
339344
}
340345
}
341346

@@ -353,3 +358,56 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
353358

354359
Rc::new(sg)
355360
}
361+
362+
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
363+
/// string.
364+
fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option<String> {
365+
use std::fmt::Write;
366+
367+
let trait_ref = if let Some(tr) = tcx.impl_trait_ref(impl_def_id) {
368+
tr
369+
} else {
370+
return None;
371+
};
372+
373+
let mut w = "impl".to_owned();
374+
375+
let substs = Substs::identity_for_item(tcx, impl_def_id);
376+
377+
// FIXME: Currently only handles ?Sized.
378+
// Needs to support ?Move and ?DynSized when they are implemented.
379+
let mut types_without_default_bounds = FxHashSet::default();
380+
let sized_trait = tcx.lang_items().sized_trait();
381+
382+
if !substs.is_noop() {
383+
types_without_default_bounds.extend(substs.types());
384+
w.push('<');
385+
w.push_str(&substs.iter().map(|k| k.to_string()).collect::<Vec<_>>().join(", "));
386+
w.push('>');
387+
}
388+
389+
write!(w, " {} for {}", trait_ref, tcx.type_of(impl_def_id)).unwrap();
390+
391+
// The predicates will contain default bounds like `T: Sized`. We need to
392+
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
393+
let predicates = tcx.predicates_of(impl_def_id).predicates;
394+
let mut pretty_predicates = Vec::with_capacity(predicates.len());
395+
for p in predicates {
396+
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
397+
if Some(poly_trait_ref.def_id()) == sized_trait {
398+
types_without_default_bounds.remove(poly_trait_ref.self_ty());
399+
continue;
400+
}
401+
}
402+
pretty_predicates.push(p.to_string());
403+
}
404+
for ty in types_without_default_bounds {
405+
pretty_predicates.push(format!("{}: ?Sized", ty));
406+
}
407+
if !pretty_predicates.is_empty() {
408+
write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
409+
}
410+
411+
w.push(';');
412+
Some(w)
413+
}

src/librustc/ty/subst.rs

+13
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ impl<'tcx> fmt::Debug for Kind<'tcx> {
107107
}
108108
}
109109

110+
impl<'tcx> fmt::Display for Kind<'tcx> {
111+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112+
if let Some(ty) = self.as_type() {
113+
write!(f, "{}", ty)
114+
} else if let Some(r) = self.as_region() {
115+
write!(f, "{}", r)
116+
} else {
117+
// FIXME(RFC 2000): extend this if/else chain when we support const generic.
118+
unimplemented!();
119+
}
120+
}
121+
}
122+
110123
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
111124
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
112125
if let Some(ty) = self.as_type() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2017 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+
use std::marker::PhantomData;
12+
13+
pub trait External {}
14+
15+
pub struct M<'a, 'b, 'c, T, U, V> {
16+
a: PhantomData<&'a ()>,
17+
b: PhantomData<&'b ()>,
18+
c: PhantomData<&'c ()>,
19+
d: PhantomData<T>,
20+
e: PhantomData<U>,
21+
f: PhantomData<V>,
22+
}
23+
24+
impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
25+
where
26+
'b: 'a,
27+
T: 'a,
28+
U: (FnOnce(T) -> V) + 'static,
29+
V: Iterator<Item=T> + Clone,
30+
W: std::ops::Add,
31+
W::Output: Copy,
32+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2017 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+
// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
12+
13+
pub trait LolTo<T> {
14+
fn convert_to(&self) -> T;
15+
}
16+
17+
pub trait LolInto<T>: Sized {
18+
fn convert_into(self) -> T;
19+
}
20+
21+
pub trait LolFrom<T> {
22+
fn from(T) -> Self;
23+
}
24+
25+
impl<'a, T: ?Sized, U> LolInto<U> for &'a T where T: LolTo<U> {
26+
fn convert_into(self) -> U {
27+
self.convert_to()
28+
}
29+
}
30+
31+
impl<T, U> LolFrom<T> for U where T: LolInto<U> {
32+
fn from(t: T) -> U {
33+
t.convert_into()
34+
}
35+
}

src/test/ui/e0119/complex-impl.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 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+
// aux-build:complex_impl_support.rs
12+
13+
extern crate complex_impl_support;
14+
15+
use complex_impl_support::{External, M};
16+
17+
struct Q;
18+
19+
impl<R> External for (Q, R) {}
20+
21+
fn main() {}

src/test/ui/e0119/complex-impl.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`:
2+
--> $DIR/complex-impl.rs:19:1
3+
|
4+
19 | impl<R> External for (Q, R) {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: conflicting implementation in crate `complex_impl_support`:
8+
- impl<'a, 'b, 'c, T, U, V, W> complex_impl_support::External for (T, complex_impl_support::M<'a, 'b, 'c, std::boxed::Box<U>, V, W>)
9+
where <U as std::ops::FnOnce<(T,)>>::Output == V, <V as std::iter::Iterator>::Item == T, 'b : 'a, T : 'a, U: std::ops::FnOnce<(T,)>, U : 'static, V: std::iter::Iterator, V: std::clone::Clone, W: std::ops::Add, <W as std::ops::Add>::Output: std::marker::Copy;
10+
11+
error[E0210]: type parameter `R` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter
12+
--> $DIR/complex-impl.rs:19:1
13+
|
14+
19 | impl<R> External for (Q, R) {}
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: aborting due to 2 previous errors
18+
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2017 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+
#![feature(try_from)]
12+
13+
use std::marker::PhantomData;
14+
use std::convert::{TryFrom, AsRef};
15+
16+
struct Q;
17+
impl AsRef<Q> for Box<Q> {
18+
fn as_ref(&self) -> &Q {
19+
&**self
20+
}
21+
}
22+
23+
struct S;
24+
impl From<S> for S {
25+
fn from(s: S) -> S {
26+
s
27+
}
28+
}
29+
30+
struct X;
31+
impl TryFrom<X> for X {
32+
type Error = ();
33+
fn try_from(u: X) -> Result<X, ()> {
34+
Ok(u)
35+
}
36+
}
37+
38+
fn main() {}
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
2+
--> $DIR/conflict-with-std.rs:17:1
3+
|
4+
17 | / impl AsRef<Q> for Box<Q> {
5+
18 | | fn as_ref(&self) -> &Q {
6+
19 | | &**self
7+
20 | | }
8+
21 | | }
9+
| |_^
10+
|
11+
= note: conflicting implementation in crate `alloc`:
12+
- impl<T> std::convert::AsRef<T> for std::boxed::Box<T>
13+
where T: ?Sized;
14+
15+
error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
16+
--> $DIR/conflict-with-std.rs:24:1
17+
|
18+
24 | / impl From<S> for S {
19+
25 | | fn from(s: S) -> S {
20+
26 | | s
21+
27 | | }
22+
28 | | }
23+
| |_^
24+
|
25+
= note: conflicting implementation in crate `core`:
26+
- impl<T> std::convert::From<T> for T;
27+
28+
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
29+
--> $DIR/conflict-with-std.rs:31:1
30+
|
31+
31 | / impl TryFrom<X> for X {
32+
32 | | type Error = ();
33+
33 | | fn try_from(u: X) -> Result<X, ()> {
34+
34 | | Ok(u)
35+
35 | | }
36+
36 | | }
37+
| |_^
38+
|
39+
= note: conflicting implementation in crate `core`:
40+
- impl<T, U> std::convert::TryFrom<U> for T
41+
where T: std::convert::From<U>;
42+
43+
error: aborting due to 3 previous errors
44+

src/test/ui/e0119/issue-23563.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 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+
// aux-build:issue_23563_a.rs
12+
13+
// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
14+
15+
extern crate issue_23563_a as a;
16+
17+
use a::LolFrom;
18+
use a::LolInto;
19+
use a::LolTo;
20+
21+
struct LocalType<T>(Option<T>);
22+
23+
impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
24+
fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
25+
}
26+
27+
impl<T> LolInto<LocalType<T>> for LocalType<T> {
28+
fn convert_into(self) -> LocalType<T> {
29+
self
30+
}
31+
}
32+
33+
impl LolTo<LocalType<u8>> for [u8] {
34+
fn convert_to(&self) -> LocalType<u8> {
35+
LocalType(None)
36+
}
37+
}
38+
39+
fn main() {}

src/test/ui/e0119/issue-23563.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `a::LolFrom<&[_]>` for type `LocalType<_>`:
2+
--> $DIR/issue-23563.rs:23:1
3+
|
4+
23 | / impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
5+
24 | | fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
6+
25 | | }
7+
| |_^
8+
|
9+
= note: conflicting implementation in crate `issue_23563_a`:
10+
- impl<T, U> a::LolFrom<T> for U
11+
where T: a::LolInto<U>;
12+
13+
error: aborting due to previous error
14+

src/test/ui/e0119/issue-27403.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 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+
pub struct GenX<S> {
12+
inner: S,
13+
}
14+
15+
impl<S> Into<S> for GenX<S> {
16+
fn into(self) -> S {
17+
self.inner
18+
}
19+
}
20+
21+
fn main() {}

src/test/ui/e0119/issue-27403.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`:
2+
--> $DIR/issue-27403.rs:15:1
3+
|
4+
15 | / impl<S> Into<S> for GenX<S> {
5+
16 | | fn into(self) -> S {
6+
17 | | self.inner
7+
18 | | }
8+
19 | | }
9+
| |_^
10+
|
11+
= note: conflicting implementation in crate `core`:
12+
- impl<T, U> std::convert::Into<U> for T
13+
where U: std::convert::From<T>;
14+
15+
error: aborting due to previous error
16+

0 commit comments

Comments
 (0)