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
```
This commit is contained in:
bors 2017-10-25 02:24:03 +00:00
commit 6e61bbabe4
16 changed files with 428 additions and 2 deletions

View File

@ -20,7 +20,7 @@
use super::{SelectionContext, FulfillmentContext};
use super::util::impl_trait_ref_and_oblig;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use hir::def_id::DefId;
use infer::{InferCtxt, InferOk};
use ty::subst::{Subst, Substs};
@ -335,7 +335,12 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
|ty| format!(" for `{}`", ty))));
}
Err(cname) => {
err.note(&format!("conflicting implementation in crate `{}`", cname));
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
Some(s) => format!(
"conflicting implementation in crate `{}`:\n- {}", cname, s),
None => format!("conflicting implementation in crate `{}`", cname),
};
err.note(&msg);
}
}
@ -353,3 +358,56 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
Rc::new(sg)
}
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
/// string.
fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option<String> {
use std::fmt::Write;
let trait_ref = if let Some(tr) = tcx.impl_trait_ref(impl_def_id) {
tr
} else {
return None;
};
let mut w = "impl".to_owned();
let substs = Substs::identity_for_item(tcx, impl_def_id);
// FIXME: Currently only handles ?Sized.
// Needs to support ?Move and ?DynSized when they are implemented.
let mut types_without_default_bounds = FxHashSet::default();
let sized_trait = tcx.lang_items().sized_trait();
if !substs.is_noop() {
types_without_default_bounds.extend(substs.types());
w.push('<');
w.push_str(&substs.iter().map(|k| k.to_string()).collect::<Vec<_>>().join(", "));
w.push('>');
}
write!(w, " {} for {}", trait_ref, tcx.type_of(impl_def_id)).unwrap();
// The predicates will contain default bounds like `T: Sized`. We need to
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
let predicates = tcx.predicates_of(impl_def_id).predicates;
let mut pretty_predicates = Vec::with_capacity(predicates.len());
for p in predicates {
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
if Some(poly_trait_ref.def_id()) == sized_trait {
types_without_default_bounds.remove(poly_trait_ref.self_ty());
continue;
}
}
pretty_predicates.push(p.to_string());
}
for ty in types_without_default_bounds {
pretty_predicates.push(format!("{}: ?Sized", ty));
}
if !pretty_predicates.is_empty() {
write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
}
w.push(';');
Some(w)
}

View File

@ -107,6 +107,19 @@ impl<'tcx> fmt::Debug for Kind<'tcx> {
}
}
impl<'tcx> fmt::Display for Kind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ty) = self.as_type() {
write!(f, "{}", ty)
} else if let Some(r) = self.as_region() {
write!(f, "{}", r)
} else {
// FIXME(RFC 2000): extend this if/else chain when we support const generic.
unimplemented!();
}
}
}
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
if let Some(ty) = self.as_type() {

View File

@ -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.
use std::marker::PhantomData;
pub trait External {}
pub struct M<'a, 'b, 'c, T, U, V> {
a: PhantomData<&'a ()>,
b: PhantomData<&'b ()>,
c: PhantomData<&'c ()>,
d: PhantomData<T>,
e: PhantomData<U>,
f: PhantomData<V>,
}
impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
where
'b: 'a,
T: 'a,
U: (FnOnce(T) -> V) + 'static,
V: Iterator<Item=T> + Clone,
W: std::ops::Add,
W::Output: Copy,
{}

View File

@ -0,0 +1,35 @@
// 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.
// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
pub trait LolTo<T> {
fn convert_to(&self) -> T;
}
pub trait LolInto<T>: Sized {
fn convert_into(self) -> T;
}
pub trait LolFrom<T> {
fn from(T) -> Self;
}
impl<'a, T: ?Sized, U> LolInto<U> for &'a T where T: LolTo<U> {
fn convert_into(self) -> U {
self.convert_to()
}
}
impl<T, U> LolFrom<T> for U where T: LolInto<U> {
fn from(t: T) -> U {
t.convert_into()
}
}

View File

@ -0,0 +1,21 @@
// 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.
// aux-build:complex_impl_support.rs
extern crate complex_impl_support;
use complex_impl_support::{External, M};
struct Q;
impl<R> External for (Q, R) {}
fn main() {}

View File

@ -0,0 +1,18 @@
error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`:
--> $DIR/complex-impl.rs:19:1
|
19 | impl<R> External for (Q, R) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `complex_impl_support`:
- 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>)
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;
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
--> $DIR/complex-impl.rs:19:1
|
19 | impl<R> External for (Q, R) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,38 @@
// 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.
#![feature(try_from)]
use std::marker::PhantomData;
use std::convert::{TryFrom, AsRef};
struct Q;
impl AsRef<Q> for Box<Q> {
fn as_ref(&self) -> &Q {
&**self
}
}
struct S;
impl From<S> for S {
fn from(s: S) -> S {
s
}
}
struct X;
impl TryFrom<X> for X {
type Error = ();
fn try_from(u: X) -> Result<X, ()> {
Ok(u)
}
}
fn main() {}

View File

@ -0,0 +1,44 @@
error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
--> $DIR/conflict-with-std.rs:17:1
|
17 | / impl AsRef<Q> for Box<Q> {
18 | | fn as_ref(&self) -> &Q {
19 | | &**self
20 | | }
21 | | }
| |_^
|
= note: conflicting implementation in crate `alloc`:
- impl<T> std::convert::AsRef<T> for std::boxed::Box<T>
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
--> $DIR/conflict-with-std.rs:24:1
|
24 | / impl From<S> for S {
25 | | fn from(s: S) -> S {
26 | | s
27 | | }
28 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
--> $DIR/conflict-with-std.rs:31:1
|
31 | / impl TryFrom<X> for X {
32 | | type Error = ();
33 | | fn try_from(u: X) -> Result<X, ()> {
34 | | Ok(u)
35 | | }
36 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where T: std::convert::From<U>;
error: aborting due to 3 previous errors

View File

@ -0,0 +1,39 @@
// 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.
// aux-build:issue_23563_a.rs
// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
extern crate issue_23563_a as a;
use a::LolFrom;
use a::LolInto;
use a::LolTo;
struct LocalType<T>(Option<T>);
impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
}
impl<T> LolInto<LocalType<T>> for LocalType<T> {
fn convert_into(self) -> LocalType<T> {
self
}
}
impl LolTo<LocalType<u8>> for [u8] {
fn convert_to(&self) -> LocalType<u8> {
LocalType(None)
}
}
fn main() {}

View File

@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `a::LolFrom<&[_]>` for type `LocalType<_>`:
--> $DIR/issue-23563.rs:23:1
|
23 | / impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
24 | | fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
25 | | }
| |_^
|
= note: conflicting implementation in crate `issue_23563_a`:
- impl<T, U> a::LolFrom<T> for U
where T: a::LolInto<U>;
error: aborting due to previous error

View File

@ -0,0 +1,21 @@
// 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.
pub struct GenX<S> {
inner: S,
}
impl<S> Into<S> for GenX<S> {
fn into(self) -> S {
self.inner
}
}
fn main() {}

View File

@ -0,0 +1,16 @@
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

View File

@ -0,0 +1,17 @@
// 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.
use std::ops::Deref;
struct Foo;
impl<Foo> Deref for Foo { }
fn main() {}

View File

@ -0,0 +1,18 @@
error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`:
--> $DIR/issue-28981.rs:15:1
|
15 | impl<Foo> Deref for Foo { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<'a, T> std::ops::Deref for &'a T
where T: ?Sized;
error[E0210]: type parameter `Foo` 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
--> $DIR/issue-28981.rs:15:1
|
15 | impl<Foo> Deref for Foo { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,27 @@
// 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.
// Ref: https://stackoverflow.com/q/37347311
trait Storage {
type Error;
}
enum MyError<S: Storage> {
StorageProblem(S::Error),
}
impl<S: Storage> From<S::Error> for MyError<S> {
fn from(error: S::Error) -> MyError<S> {
MyError::StorageProblem(error)
}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> $DIR/so-37347311.rs:21:1
|
21 | / impl<S: Storage> From<S::Error> for MyError<S> {
22 | | fn from(error: S::Error) -> MyError<S> {
23 | | MyError::StorageProblem(error)
24 | | }
25 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
error: aborting due to previous error