Skip to content

Improve diagnostic of E0119 with extern crate, try to print the conflicting impl. #45455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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)
}
13 changes: 13 additions & 0 deletions src/librustc/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/e0119/auxiliary/complex_impl_support.rs
Original file line number Diff line number Diff line change
@@ -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,
{}
35 changes: 35 additions & 0 deletions src/test/ui/e0119/auxiliary/issue_23563_a.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
21 changes: 21 additions & 0 deletions src/test/ui/e0119/complex-impl.rs
Original file line number Diff line number Diff line change
@@ -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() {}
18 changes: 18 additions & 0 deletions src/test/ui/e0119/complex-impl.stderr
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearly we could do a better job on the formatting here, both for individual where clauses (which could be simplified) and for the listing itself (which could be spread across multiple lines or something. Still, not sure it's worth blocking this PR on that.


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

38 changes: 38 additions & 0 deletions src/test/ui/e0119/conflict-with-std.rs
Original file line number Diff line number Diff line change
@@ -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() {}
44 changes: 44 additions & 0 deletions src/test/ui/e0119/conflict-with-std.stderr
Original file line number Diff line number Diff line change
@@ -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

39 changes: 39 additions & 0 deletions src/test/ui/e0119/issue-23563.rs
Original file line number Diff line number Diff line change
@@ -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() {}
14 changes: 14 additions & 0 deletions src/test/ui/e0119/issue-23563.stderr
Original file line number Diff line number Diff line change
@@ -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

21 changes: 21 additions & 0 deletions src/test/ui/e0119/issue-27403.rs
Original file line number Diff line number Diff line change
@@ -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() {}
16 changes: 16 additions & 0 deletions src/test/ui/e0119/issue-27403.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading