Skip to content

Commit 0f6f66f

Browse files
committed
Auto merge of #66561 - TimoFreiberg:trait-name-report, r=estebank
Add version mismatch help message for unimplemented trait Improves issue #22750 The error reporting for E0277 (the trait `X` is not implemented for `Foo`) now checks whether `Foo` implements a trait with the same path as `X`, which probably means that the programmer wanted to actually use only one version of the trait `X` instead of the two. Still open: * the same diagnostic should be added for [the trait method case](#22750 (comment)) * Showing the real crate versions would be nice, but rustc currently doesn't have that information [according to Esteban](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/diagnostics.20for.20crate.20version.20mismatch/near/180572989)
2 parents 2626f3d + 2a0292f commit 0f6f66f

File tree

5 files changed

+176
-7
lines changed

5 files changed

+176
-7
lines changed

src/librustc/traits/error_reporting.rs

+39
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use std::fmt;
3838
use syntax::ast;
3939
use syntax::symbol::{sym, kw};
4040
use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
41+
use rustc::hir::def_id::LOCAL_CRATE;
4142

4243
use rustc_error_codes::*;
4344

@@ -799,6 +800,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
799800
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
800801
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
801802
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
803+
self.note_version_mismatch(&mut err, &trait_ref);
802804

803805
// Try to report a help message
804806
if !trait_ref.has_infer_types() &&
@@ -1050,6 +1052,43 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10501052
err.emit();
10511053
}
10521054

1055+
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
1056+
/// with the same path as `trait_ref`, a help message about
1057+
/// a probable version mismatch is added to `err`
1058+
fn note_version_mismatch(
1059+
&self,
1060+
err: &mut DiagnosticBuilder<'_>,
1061+
trait_ref: &ty::PolyTraitRef<'tcx>,
1062+
) {
1063+
let get_trait_impl = |trait_def_id| {
1064+
let mut trait_impl = None;
1065+
self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| {
1066+
if trait_impl.is_none() {
1067+
trait_impl = Some(impl_def_id);
1068+
}
1069+
});
1070+
trait_impl
1071+
};
1072+
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
1073+
let all_traits = self.tcx.all_traits(LOCAL_CRATE);
1074+
let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
1075+
.iter()
1076+
.filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
1077+
.filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
1078+
.collect();
1079+
for trait_with_same_path in traits_with_same_path {
1080+
if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
1081+
let impl_span = self.tcx.def_span(impl_def_id);
1082+
err.span_help(impl_span, "trait impl with same name found");
1083+
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
1084+
let crate_msg = format!(
1085+
"Perhaps two different versions of crate `{}` are being used?",
1086+
trait_crate
1087+
);
1088+
err.note(&crate_msg);
1089+
}
1090+
}
1091+
}
10531092
fn suggest_restricting_param_bound(
10541093
&self,
10551094
err: &mut DiagnosticBuilder<'_>,
+5-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
pub struct Foo;
1+
pub trait Bar {}
22

3-
pub trait Bar{}
3+
pub fn try_foo(x: impl Bar) {}
44

5-
pub fn bar() -> Box<Bar> {
6-
unimplemented!()
5+
pub struct ImplementsTraitForUsize<T> {
6+
_marker: std::marker::PhantomData<T>,
77
}
88

9-
10-
pub fn try_foo(x: Foo){}
11-
pub fn try_bar(x: Box<Bar>){}
9+
impl Bar for ImplementsTraitForUsize<usize> {}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub struct Foo;
2+
3+
pub trait Bar {}
4+
5+
impl Bar for Foo {}
6+
7+
pub struct DoesNotImplementTrait;
8+
9+
pub struct ImplementsWrongTraitConditionally<T> {
10+
_marker: std::marker::PhantomData<T>,
11+
}
12+
13+
impl Bar for ImplementsWrongTraitConditionally<isize> {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// aux-build:crate_a1.rs
2+
// aux-build:crate_a2.rs
3+
4+
// Issue 22750
5+
// This tests the extra help message reported when a trait bound
6+
// is not met but the struct implements a trait with the same path.
7+
8+
fn main() {
9+
let foo = {
10+
extern crate crate_a2 as a;
11+
a::Foo
12+
};
13+
14+
let implements_no_traits = {
15+
extern crate crate_a2 as a;
16+
a::DoesNotImplementTrait
17+
};
18+
19+
let other_variant_implements_mismatched_trait = {
20+
extern crate crate_a2 as a;
21+
a::ImplementsWrongTraitConditionally { _marker: std::marker::PhantomData::<isize> }
22+
};
23+
24+
let other_variant_implements_correct_trait = {
25+
extern crate crate_a1 as a;
26+
a::ImplementsTraitForUsize { _marker: std::marker::PhantomData::<isize> }
27+
};
28+
29+
{
30+
extern crate crate_a1 as a;
31+
a::try_foo(foo);
32+
//~^ ERROR E0277
33+
//~| trait impl with same name found
34+
//~| Perhaps two different versions of crate `crate_a2`
35+
36+
// We don't want to see the "version mismatch" help message here
37+
// because `implements_no_traits` has no impl for `Foo`
38+
a::try_foo(implements_no_traits);
39+
//~^ ERROR E0277
40+
41+
// We don't want to see the "version mismatch" help message here
42+
// because `other_variant_implements_mismatched_trait`
43+
// does not have an impl for its `<isize>` variant,
44+
// only for its `<usize>` variant.
45+
a::try_foo(other_variant_implements_mismatched_trait);
46+
//~^ ERROR E0277
47+
48+
// We don't want to see the "version mismatch" help message here
49+
// because `ImplementsTraitForUsize` only has
50+
// impls for the correct trait where the path is not misleading.
51+
a::try_foo(other_variant_implements_correct_trait);
52+
//~^ ERROR E0277
53+
//~| the following implementations were found:
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
error[E0277]: the trait bound `main::a::Foo: main::a::Bar` is not satisfied
2+
--> $DIR/trait-bounds-same-crate-name.rs:31:20
3+
|
4+
LL | a::try_foo(foo);
5+
| ^^^ the trait `main::a::Bar` is not implemented for `main::a::Foo`
6+
|
7+
::: $DIR/auxiliary/crate_a1.rs:3:24
8+
|
9+
LL | pub fn try_foo(x: impl Bar) {}
10+
| --- required by this bound in `main::a::try_foo`
11+
|
12+
help: trait impl with same name found
13+
--> $DIR/auxiliary/crate_a2.rs:5:1
14+
|
15+
LL | impl Bar for Foo {}
16+
| ^^^^^^^^^^^^^^^^^^^
17+
= note: Perhaps two different versions of crate `crate_a2` are being used?
18+
19+
error[E0277]: the trait bound `main::a::DoesNotImplementTrait: main::a::Bar` is not satisfied
20+
--> $DIR/trait-bounds-same-crate-name.rs:38:20
21+
|
22+
LL | a::try_foo(implements_no_traits);
23+
| ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::DoesNotImplementTrait`
24+
|
25+
::: $DIR/auxiliary/crate_a1.rs:3:24
26+
|
27+
LL | pub fn try_foo(x: impl Bar) {}
28+
| --- required by this bound in `main::a::try_foo`
29+
30+
error[E0277]: the trait bound `main::a::ImplementsWrongTraitConditionally<isize>: main::a::Bar` is not satisfied
31+
--> $DIR/trait-bounds-same-crate-name.rs:45:20
32+
|
33+
LL | a::try_foo(other_variant_implements_mismatched_trait);
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsWrongTraitConditionally<isize>`
35+
|
36+
::: $DIR/auxiliary/crate_a1.rs:3:24
37+
|
38+
LL | pub fn try_foo(x: impl Bar) {}
39+
| --- required by this bound in `main::a::try_foo`
40+
|
41+
help: trait impl with same name found
42+
--> $DIR/auxiliary/crate_a2.rs:13:1
43+
|
44+
LL | impl Bar for ImplementsWrongTraitConditionally<isize> {}
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46+
= note: Perhaps two different versions of crate `crate_a2` are being used?
47+
48+
error[E0277]: the trait bound `main::a::ImplementsTraitForUsize<isize>: main::a::Bar` is not satisfied
49+
--> $DIR/trait-bounds-same-crate-name.rs:51:20
50+
|
51+
LL | a::try_foo(other_variant_implements_correct_trait);
52+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsTraitForUsize<isize>`
53+
|
54+
::: $DIR/auxiliary/crate_a1.rs:3:24
55+
|
56+
LL | pub fn try_foo(x: impl Bar) {}
57+
| --- required by this bound in `main::a::try_foo`
58+
|
59+
= help: the following implementations were found:
60+
<main::a::ImplementsTraitForUsize<usize> as main::a::Bar>
61+
62+
error: aborting due to 4 previous errors
63+
64+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)