Auto merge of #144674 - rperier:add_note_if_a_type_impl_a_trait_with_the_same_name, r=lcnr
Add a diagnostic for similarly named traits cc rust-lang/rust#133123 This is a first proposal, suggestions are welcome
This commit is contained in:
commit
11339a0ef5
15 changed files with 386 additions and 528 deletions
|
|
@ -4212,7 +4212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err: &mut Diag<'_>,
|
||||
item_def_id: DefId,
|
||||
hir_id: hir::HirId,
|
||||
rcvr_ty: Option<Ty<'_>>,
|
||||
rcvr_ty: Option<Ty<'tcx>>,
|
||||
) -> bool {
|
||||
let hir_id = self.tcx.parent_hir_id(hir_id);
|
||||
let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
|
||||
|
|
@ -4223,49 +4223,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !self.tcx.is_trait(trait_def_id) {
|
||||
return false;
|
||||
}
|
||||
let krate = self.tcx.crate_name(trait_def_id.krate);
|
||||
let name = self.tcx.item_name(trait_def_id);
|
||||
let candidates: Vec<_> = traits
|
||||
.iter()
|
||||
.filter(|c| {
|
||||
c.def_id.krate != trait_def_id.krate
|
||||
&& self.tcx.crate_name(c.def_id.krate) == krate
|
||||
&& self.tcx.item_name(c.def_id) == name
|
||||
})
|
||||
.map(|c| (c.def_id, c.import_ids.get(0).cloned()))
|
||||
.collect();
|
||||
if candidates.is_empty() {
|
||||
let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else {
|
||||
return false;
|
||||
}
|
||||
let item_span = self.tcx.def_span(item_def_id);
|
||||
let msg = format!(
|
||||
"there are multiple different versions of crate `{krate}` in the dependency graph",
|
||||
);
|
||||
let trait_span = self.tcx.def_span(trait_def_id);
|
||||
let mut multi_span: MultiSpan = trait_span.into();
|
||||
multi_span.push_span_label(trait_span, "this is the trait that is needed".to_string());
|
||||
let descr = self.tcx.associated_item(item_def_id).descr();
|
||||
let rcvr_ty =
|
||||
rcvr_ty.map(|t| format!("`{t}`")).unwrap_or_else(|| "the receiver".to_string());
|
||||
multi_span
|
||||
.push_span_label(item_span, format!("the {descr} is available for {rcvr_ty} here"));
|
||||
for (def_id, import_def_id) in candidates {
|
||||
if let Some(import_def_id) = import_def_id {
|
||||
multi_span.push_span_label(
|
||||
self.tcx.def_span(import_def_id),
|
||||
format!(
|
||||
"`{name}` imported here doesn't correspond to the right version of crate \
|
||||
`{krate}`",
|
||||
),
|
||||
);
|
||||
}
|
||||
multi_span.push_span_label(
|
||||
self.tcx.def_span(def_id),
|
||||
"this is the trait that was imported".to_string(),
|
||||
);
|
||||
}
|
||||
err.span_note(multi_span, msg);
|
||||
true
|
||||
};
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter());
|
||||
let trait_pred = ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::PredicatePolarity::Positive,
|
||||
});
|
||||
let obligation = Obligation::new(self.tcx, self.misc(rcvr.span), self.param_env, trait_ref);
|
||||
self.err_ctxt().note_different_trait_with_same_name(err, &obligation, trait_pred)
|
||||
}
|
||||
|
||||
/// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
|
||||
|
|
|
|||
|
|
@ -51,11 +51,8 @@ use std::path::PathBuf;
|
|||
use std::{cmp, fmt, iter};
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::join_path_syms;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -66,15 +63,12 @@ use rustc_middle::bug;
|
|||
use rustc_middle::dep_graph::DepContext;
|
||||
use rustc_middle::traits::PatternOriginExpr;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt};
|
||||
use rustc_middle::ty::print::{
|
||||
PrintError, PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths,
|
||||
};
|
||||
use rustc_middle::ty::print::{PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths};
|
||||
use rustc_middle::ty::{
|
||||
self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym};
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::error_reporting::TypeErrCtxt;
|
||||
|
|
@ -216,201 +210,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
/// Adds a note if the types come from similarly named crates
|
||||
fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) -> bool {
|
||||
// FIXME(estebank): unify with `report_similar_impl_candidates`. The message is similar,
|
||||
// even if the logic needed to detect the case is very different.
|
||||
use hir::def_id::CrateNum;
|
||||
use rustc_hir::definitions::DisambiguatedDefPathData;
|
||||
use ty::GenericArg;
|
||||
use ty::print::Printer;
|
||||
|
||||
struct ConflictingPathPrinter<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
segments: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl<'tcx> Printer<'tcx> for ConflictingPathPrinter<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
|
||||
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
|
||||
}
|
||||
|
||||
fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
|
||||
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
|
||||
}
|
||||
|
||||
fn print_dyn_existential(
|
||||
&mut self,
|
||||
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
) -> Result<(), PrintError> {
|
||||
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
|
||||
}
|
||||
|
||||
fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
|
||||
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
|
||||
}
|
||||
|
||||
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
|
||||
self.segments = vec![self.tcx.crate_name(cnum)];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_path_with_qualified(
|
||||
&mut self,
|
||||
_self_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<(), PrintError> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn print_path_with_impl(
|
||||
&mut self,
|
||||
_print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
|
||||
_self_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<(), PrintError> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn print_path_with_simple(
|
||||
&mut self,
|
||||
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
) -> Result<(), PrintError> {
|
||||
print_prefix(self)?;
|
||||
self.segments.push(disambiguated_data.as_sym(true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_path_with_generic_args(
|
||||
&mut self,
|
||||
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
|
||||
_args: &[GenericArg<'tcx>],
|
||||
) -> Result<(), PrintError> {
|
||||
print_prefix(self)
|
||||
}
|
||||
}
|
||||
|
||||
let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId, ty: &str| -> bool {
|
||||
// Only report definitions from different crates. If both definitions
|
||||
// are from a local module we could have false positives, e.g.
|
||||
// let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
|
||||
if did1.krate != did2.krate {
|
||||
let abs_path = |def_id| {
|
||||
let mut p = ConflictingPathPrinter { tcx: self.tcx, segments: vec![] };
|
||||
p.print_def_path(def_id, &[]).map(|_| p.segments)
|
||||
};
|
||||
|
||||
// We compare strings because DefPath can be different for imported and
|
||||
// non-imported crates.
|
||||
let expected_str = self.tcx.def_path_str(did1);
|
||||
let found_str = self.tcx.def_path_str(did2);
|
||||
let Ok(expected_abs) = abs_path(did1) else { return false };
|
||||
let Ok(found_abs) = abs_path(did2) else { return false };
|
||||
let same_path = expected_str == found_str || expected_abs == found_abs;
|
||||
if same_path {
|
||||
// We want to use as unique a type path as possible. If both types are "locally
|
||||
// known" by the same name, we use the "absolute path" which uses the original
|
||||
// crate name instead.
|
||||
let (expected, found) = if expected_str == found_str {
|
||||
(join_path_syms(&expected_abs), join_path_syms(&found_abs))
|
||||
} else {
|
||||
(expected_str, found_str)
|
||||
};
|
||||
|
||||
// We've displayed "expected `a::b`, found `a::b`". We add context to
|
||||
// differentiate the different cases where that might happen.
|
||||
let expected_crate_name = self.tcx.crate_name(did1.krate);
|
||||
let found_crate_name = self.tcx.crate_name(did2.krate);
|
||||
let same_crate = expected_crate_name == found_crate_name;
|
||||
let expected_sp = self.tcx.def_span(did1);
|
||||
let found_sp = self.tcx.def_span(did2);
|
||||
|
||||
let both_direct_dependencies = if !did1.is_local()
|
||||
&& !did2.is_local()
|
||||
&& let Some(data1) = self.tcx.extern_crate(did1.krate)
|
||||
&& let Some(data2) = self.tcx.extern_crate(did2.krate)
|
||||
&& data1.dependency_of == LOCAL_CRATE
|
||||
&& data2.dependency_of == LOCAL_CRATE
|
||||
{
|
||||
// If both crates are directly depended on, we don't want to mention that
|
||||
// in the final message, as it is redundant wording.
|
||||
// We skip the case of semver trick, where one version of the local crate
|
||||
// depends on another version of itself by checking that both crates at play
|
||||
// are not the current one.
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut span: MultiSpan = vec![expected_sp, found_sp].into();
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(did1),
|
||||
format!("this is the expected {ty} `{expected}`"),
|
||||
);
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(did2),
|
||||
format!("this is the found {ty} `{found}`"),
|
||||
);
|
||||
for def_id in [did1, did2] {
|
||||
let crate_name = self.tcx.crate_name(def_id.krate);
|
||||
if !def_id.is_local()
|
||||
&& let Some(data) = self.tcx.extern_crate(def_id.krate)
|
||||
{
|
||||
let descr = if same_crate {
|
||||
"one version of".to_string()
|
||||
} else {
|
||||
format!("one {ty} comes from")
|
||||
};
|
||||
let dependency = if both_direct_dependencies {
|
||||
if let rustc_session::cstore::ExternCrateSource::Extern(def_id) =
|
||||
data.src
|
||||
&& let Some(name) = self.tcx.opt_item_name(def_id)
|
||||
{
|
||||
format!(", which is renamed locally to `{name}`")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
} else if data.dependency_of == LOCAL_CRATE {
|
||||
", as a direct dependency of the current crate".to_string()
|
||||
} else {
|
||||
let dep = self.tcx.crate_name(data.dependency_of);
|
||||
format!(", as a dependency of crate `{dep}`")
|
||||
};
|
||||
span.push_span_label(
|
||||
data.span,
|
||||
format!("{descr} crate `{crate_name}` used here{dependency}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
let msg = if (did1.is_local() || did2.is_local()) && same_crate {
|
||||
format!(
|
||||
"the crate `{expected_crate_name}` is compiled multiple times, \
|
||||
possibly with different configurations",
|
||||
)
|
||||
} else if same_crate {
|
||||
format!(
|
||||
"two different versions of crate `{expected_crate_name}` are being \
|
||||
used; two types coming from two different versions of the same crate \
|
||||
are different types even if they look the same",
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"two types coming from two different crates are different types even \
|
||||
if they look the same",
|
||||
)
|
||||
};
|
||||
err.span_note(span, msg);
|
||||
if same_crate {
|
||||
err.help("you can use `cargo tree` to explore your dependency tree");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
match terr {
|
||||
TypeError::Sorts(ref exp_found) => {
|
||||
// if they are both "path types", there's a chance of ambiguity
|
||||
|
|
@ -418,11 +217,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) =
|
||||
(exp_found.expected.kind(), exp_found.found.kind())
|
||||
{
|
||||
return report_path_match(err, exp_adt.did(), found_adt.did(), "type");
|
||||
return self.check_same_definition_different_crate(
|
||||
err,
|
||||
exp_adt.did(),
|
||||
[found_adt.did()].into_iter(),
|
||||
|did| vec![self.tcx.def_span(did)],
|
||||
"type",
|
||||
);
|
||||
}
|
||||
}
|
||||
TypeError::Traits(ref exp_found) => {
|
||||
return report_path_match(err, exp_found.expected, exp_found.found, "trait");
|
||||
return self.check_same_definition_different_crate(
|
||||
err,
|
||||
exp_found.expected,
|
||||
[exp_found.found].into_iter(),
|
||||
|did| vec![self.tcx.def_span(did)],
|
||||
"trait",
|
||||
);
|
||||
}
|
||||
_ => (), // FIXME(#22750) handle traits and stuff
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
span,
|
||||
leaf_trait_predicate,
|
||||
);
|
||||
self.note_trait_version_mismatch(&mut err, leaf_trait_predicate);
|
||||
self.note_different_trait_with_same_name(&mut err, &obligation, leaf_trait_predicate);
|
||||
self.note_adt_version_mismatch(&mut err, leaf_trait_predicate);
|
||||
self.suggest_remove_await(&obligation, &mut err);
|
||||
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
|
||||
|
|
@ -1974,115 +1974,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
impl_candidates
|
||||
};
|
||||
|
||||
// We'll check for the case where the reason for the mismatch is that the trait comes from
|
||||
// one crate version and the type comes from another crate version, even though they both
|
||||
// are from the same crate.
|
||||
let trait_def_id = trait_pred.def_id();
|
||||
let trait_name = self.tcx.item_name(trait_def_id);
|
||||
let crate_name = self.tcx.crate_name(trait_def_id.krate);
|
||||
if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| {
|
||||
trait_name == self.tcx.item_name(trait_def_id)
|
||||
&& trait_def_id.krate != def_id.krate
|
||||
&& crate_name == self.tcx.crate_name(def_id.krate)
|
||||
}) {
|
||||
// We've found two different traits with the same name, same crate name, but
|
||||
// different crate `DefId`. We highlight the traits.
|
||||
|
||||
let found_type =
|
||||
if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() {
|
||||
Some(def.did())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let candidates = if impl_candidates.is_empty() {
|
||||
alternative_candidates(trait_def_id)
|
||||
} else {
|
||||
impl_candidates.into_iter().map(|cand| (cand.trait_ref, cand.impl_def_id)).collect()
|
||||
};
|
||||
let mut span: MultiSpan = self.tcx.def_span(trait_def_id).into();
|
||||
span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
|
||||
for (sp, label) in [trait_def_id, other_trait_def_id]
|
||||
.iter()
|
||||
// The current crate-version might depend on another version of the same crate
|
||||
// (Think "semver-trick"). Do not call `extern_crate` in that case for the local
|
||||
// crate as that doesn't make sense and ICEs (#133563).
|
||||
.filter(|def_id| !def_id.is_local())
|
||||
.filter_map(|def_id| self.tcx.extern_crate(def_id.krate))
|
||||
.map(|data| {
|
||||
let dependency = if data.dependency_of == LOCAL_CRATE {
|
||||
"direct dependency of the current crate".to_string()
|
||||
} else {
|
||||
let dep = self.tcx.crate_name(data.dependency_of);
|
||||
format!("dependency of crate `{dep}`")
|
||||
};
|
||||
(
|
||||
data.span,
|
||||
format!("one version of crate `{crate_name}` used here, as a {dependency}"),
|
||||
)
|
||||
})
|
||||
{
|
||||
span.push_span_label(sp, label);
|
||||
}
|
||||
let mut points_at_type = false;
|
||||
if let Some(found_type) = found_type {
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(found_type),
|
||||
"this type doesn't implement the required trait",
|
||||
);
|
||||
for (trait_ref, _) in candidates {
|
||||
if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind()
|
||||
&& let candidate_def_id = def.did()
|
||||
&& let Some(name) = self.tcx.opt_item_name(candidate_def_id)
|
||||
&& let Some(found) = self.tcx.opt_item_name(found_type)
|
||||
&& name == found
|
||||
&& candidate_def_id.krate != found_type.krate
|
||||
&& self.tcx.crate_name(candidate_def_id.krate)
|
||||
== self.tcx.crate_name(found_type.krate)
|
||||
{
|
||||
// A candidate was found of an item with the same name, from two separate
|
||||
// versions of the same crate, let's clarify.
|
||||
let candidate_span = self.tcx.def_span(candidate_def_id);
|
||||
span.push_span_label(
|
||||
candidate_span,
|
||||
"this type implements the required trait",
|
||||
);
|
||||
points_at_type = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
span.push_span_label(self.tcx.def_span(other_trait_def_id), "this is the found trait");
|
||||
err.highlighted_span_note(
|
||||
span,
|
||||
vec![
|
||||
StringPart::normal("there are ".to_string()),
|
||||
StringPart::highlighted("multiple different versions".to_string()),
|
||||
StringPart::normal(" of crate `".to_string()),
|
||||
StringPart::highlighted(format!("{crate_name}")),
|
||||
StringPart::normal("` in the dependency graph".to_string()),
|
||||
],
|
||||
);
|
||||
if points_at_type {
|
||||
// We only clarify that the same type from different crate versions are not the
|
||||
// same when we *find* the same type coming from different crate versions, otherwise
|
||||
// it could be that it was a type provided by a different crate than the one that
|
||||
// provides the trait, and mentioning this adds verbosity without clarification.
|
||||
err.highlighted_note(vec![
|
||||
StringPart::normal(
|
||||
"two types coming from two different versions of the same crate are \
|
||||
different types "
|
||||
.to_string(),
|
||||
),
|
||||
StringPart::highlighted("even if they look the same".to_string()),
|
||||
]);
|
||||
}
|
||||
err.highlighted_help(vec![
|
||||
StringPart::normal("you can use `".to_string()),
|
||||
StringPart::highlighted("cargo tree".to_string()),
|
||||
StringPart::normal("` to explore your dependency tree".to_string()),
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if let [single] = &impl_candidates {
|
||||
// If we have a single implementation, try to unify it with the trait ref
|
||||
// that failed. This should uncover a better hint for what *is* implemented.
|
||||
|
|
@ -2478,10 +2369,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||
/// with the same path as `trait_ref`, a help message about
|
||||
/// a probable version mismatch is added to `err`
|
||||
fn note_trait_version_mismatch(
|
||||
fn check_same_trait_different_version(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
|
|
@ -2492,46 +2380,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
trait_def_id,
|
||||
trait_pred.skip_binder().self_ty(),
|
||||
|impl_def_id| {
|
||||
trait_impls.push(impl_def_id);
|
||||
let impl_trait_header = self.tcx.impl_trait_header(impl_def_id);
|
||||
trait_impls
|
||||
.push(self.tcx.def_span(impl_trait_header.trait_ref.skip_binder().def_id));
|
||||
},
|
||||
);
|
||||
trait_impls
|
||||
};
|
||||
|
||||
let required_trait_path = self.tcx.def_path_str(trait_pred.def_id());
|
||||
let traits_with_same_path: UnordSet<_> = self
|
||||
.tcx
|
||||
.visible_traits()
|
||||
.filter(|trait_def_id| *trait_def_id != trait_pred.def_id())
|
||||
.map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id))
|
||||
.filter(|(p, _)| *p == required_trait_path)
|
||||
.collect();
|
||||
|
||||
let traits_with_same_path =
|
||||
traits_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
|
||||
let mut suggested = false;
|
||||
for (_, trait_with_same_path) in traits_with_same_path {
|
||||
let trait_impls = get_trait_impls(trait_with_same_path);
|
||||
if trait_impls.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let impl_spans: Vec<_> =
|
||||
trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
|
||||
err.span_help(
|
||||
impl_spans,
|
||||
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
|
||||
);
|
||||
self.note_two_crate_versions(trait_with_same_path, err);
|
||||
suggested = true;
|
||||
}
|
||||
suggested
|
||||
self.check_same_definition_different_crate(
|
||||
err,
|
||||
trait_pred.def_id(),
|
||||
self.tcx.visible_traits(),
|
||||
get_trait_impls,
|
||||
"trait",
|
||||
)
|
||||
}
|
||||
|
||||
fn note_two_crate_versions(&self, did: DefId, err: &mut Diag<'_>) {
|
||||
pub fn note_two_crate_versions(
|
||||
&self,
|
||||
did: DefId,
|
||||
sp: impl Into<MultiSpan>,
|
||||
err: &mut Diag<'_>,
|
||||
) {
|
||||
let crate_name = self.tcx.crate_name(did.krate);
|
||||
let crate_msg =
|
||||
format!("perhaps two different versions of crate `{crate_name}` are being used?");
|
||||
err.note(crate_msg);
|
||||
let crate_msg = format!(
|
||||
"there are multiple different versions of crate `{crate_name}` in the dependency graph"
|
||||
);
|
||||
err.span_note(sp, crate_msg);
|
||||
}
|
||||
|
||||
fn note_adt_version_mismatch(
|
||||
|
|
@ -2592,10 +2467,82 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
for (similar_item, _) in similar_items {
|
||||
err.span_help(self.tcx.def_span(similar_item), "item with same name found");
|
||||
self.note_two_crate_versions(similar_item, err);
|
||||
self.note_two_crate_versions(similar_item, MultiSpan::new(), err);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_same_name_different_path(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let mut suggested = false;
|
||||
let trait_def_id = trait_pred.def_id();
|
||||
let trait_has_same_params = |other_trait_def_id: DefId| -> bool {
|
||||
let trait_generics = self.tcx.generics_of(trait_def_id);
|
||||
let other_trait_generics = self.tcx.generics_of(other_trait_def_id);
|
||||
|
||||
if trait_generics.count() != other_trait_generics.count() {
|
||||
return false;
|
||||
}
|
||||
trait_generics.own_params.iter().zip(other_trait_generics.own_params.iter()).all(
|
||||
|(a, b)| match (&a.kind, &b.kind) {
|
||||
(ty::GenericParamDefKind::Lifetime, ty::GenericParamDefKind::Lifetime)
|
||||
| (
|
||||
ty::GenericParamDefKind::Type { .. },
|
||||
ty::GenericParamDefKind::Type { .. },
|
||||
)
|
||||
| (
|
||||
ty::GenericParamDefKind::Const { .. },
|
||||
ty::GenericParamDefKind::Const { .. },
|
||||
) => true,
|
||||
_ => false,
|
||||
},
|
||||
)
|
||||
};
|
||||
let trait_name = self.tcx.item_name(trait_def_id);
|
||||
if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| {
|
||||
trait_def_id != *def_id
|
||||
&& trait_name == self.tcx.item_name(def_id)
|
||||
&& trait_has_same_params(*def_id)
|
||||
&& self.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||
self.tcx,
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|tr| ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(self.tcx, *def_id, tr.trait_ref.args),
|
||||
..tr
|
||||
}),
|
||||
))
|
||||
}) {
|
||||
err.note(format!(
|
||||
"`{}` implements similarly named trait `{}`, but not `{}`",
|
||||
trait_pred.self_ty(),
|
||||
self.tcx.def_path_str(other_trait_def_id),
|
||||
trait_pred.print_modifiers_and_trait_path()
|
||||
));
|
||||
suggested = true;
|
||||
}
|
||||
suggested
|
||||
}
|
||||
|
||||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||
/// with the same path as `trait_ref`, a help message about a multiple different
|
||||
/// versions of the same crate is added to `err`. Otherwise if it implements another
|
||||
/// trait with the same name, a note message about a similarly named trait is added to `err`.
|
||||
pub fn note_different_trait_with_same_name(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
if self.check_same_trait_different_version(err, trait_pred) {
|
||||
return true;
|
||||
}
|
||||
self.check_same_name_different_path(err, obligation, trait_pred)
|
||||
}
|
||||
|
||||
/// Add a `::` prefix when comparing paths so that paths with just one item
|
||||
/// like "Foo" does not equal the end of "OtherFoo".
|
||||
fn comparable_path(&self, did: DefId) -> String {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
pub mod ambiguity;
|
||||
pub mod call_kind;
|
||||
mod fulfillment_errors;
|
||||
pub mod fulfillment_errors;
|
||||
pub mod on_unimplemented;
|
||||
pub mod on_unimplemented_condition;
|
||||
pub mod on_unimplemented_format;
|
||||
|
|
@ -10,6 +10,7 @@ pub mod suggestions;
|
|||
use std::{fmt, iter};
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -21,7 +22,7 @@ use rustc_infer::traits::{
|
|||
};
|
||||
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
||||
use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span};
|
||||
use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span, Symbol};
|
||||
use tracing::{info, instrument};
|
||||
|
||||
pub use self::overflow::*;
|
||||
|
|
@ -351,6 +352,80 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_extern_crate_renamed_symbol(&self, trait_def_id: DefId) -> Option<Symbol> {
|
||||
if !trait_def_id.is_local()
|
||||
&& let Some(data) = self.tcx.extern_crate(trait_def_id.krate)
|
||||
&& let rustc_session::cstore::ExternCrateSource::Extern(def_id) = data.src
|
||||
{
|
||||
self.tcx.opt_item_name(def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_same_definition_different_crate<F>(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
expected_did: DefId,
|
||||
found_dids: impl Iterator<Item = DefId>,
|
||||
get_impls: F,
|
||||
ty: &str,
|
||||
) -> bool
|
||||
where
|
||||
F: Fn(DefId) -> Vec<Span>,
|
||||
{
|
||||
let krate = self.tcx.crate_name(expected_did.krate);
|
||||
let name = self.tcx.item_name(expected_did);
|
||||
let locally_renamed_krate = self
|
||||
.get_extern_crate_renamed_symbol(expected_did)
|
||||
.map_or(None, |s| if s != krate { Some(s) } else { None });
|
||||
let definitions_with_same_path: UnordSet<_> = found_dids
|
||||
.filter(|def_id| {
|
||||
def_id.krate != expected_did.krate
|
||||
&& (locally_renamed_krate == self.get_extern_crate_renamed_symbol(*def_id)
|
||||
|| self.tcx.crate_name(def_id.krate) == krate)
|
||||
&& self.tcx.item_name(def_id) == name
|
||||
})
|
||||
.map(|def_id| (self.tcx.def_path_str(def_id), def_id))
|
||||
.collect();
|
||||
|
||||
let definitions_with_same_path =
|
||||
definitions_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
|
||||
let mut suggested = false;
|
||||
let mut trait_is_impl = false;
|
||||
|
||||
if !definitions_with_same_path.is_empty() {
|
||||
let mut span: MultiSpan = self.tcx.def_span(expected_did).into();
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(expected_did),
|
||||
format!("this is the expected {ty}"),
|
||||
);
|
||||
suggested = true;
|
||||
for (_, definition_with_same_path) in &definitions_with_same_path {
|
||||
let definitions_impls = get_impls(*definition_with_same_path);
|
||||
if definitions_impls.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for candidate_span in definitions_impls {
|
||||
span.push_span_label(candidate_span, format!("this is the found {ty}"));
|
||||
trait_is_impl = true;
|
||||
}
|
||||
}
|
||||
if !trait_is_impl {
|
||||
for (_, def_id) in definitions_with_same_path {
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(def_id),
|
||||
format!("this is the {ty} that was imported"),
|
||||
);
|
||||
}
|
||||
}
|
||||
self.note_two_crate_versions(expected_did, span, err);
|
||||
err.help("you can use `cargo tree` to explore your dependency tree");
|
||||
}
|
||||
suggested
|
||||
}
|
||||
}
|
||||
|
||||
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
//@ [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies
|
||||
|
||||
pub struct Foo;
|
||||
//[cfail2]~^ NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
|
||||
//[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
|
||||
//[cfail2]~| NOTE this is the expected type `Foo`
|
||||
//[cfail2]~| NOTE this is the expected type `circular_dependencies::Foo`
|
||||
//[cfail2]~| NOTE this is the found type `Foo`
|
||||
//[cfail2]~| NOTE this is the found type `circular_dependencies::Foo`
|
||||
//[cfail2]~^ NOTE there are multiple different versions of crate `circular_dependencies` in the dependency graph
|
||||
//[cfail2]~| NOTE there are multiple different versions of crate `circular_dependencies` in the dependency graph
|
||||
//[cfail2]~| NOTE this is the expected type
|
||||
//[cfail2]~| NOTE this is the expected type
|
||||
//[cfail2]~| NOTE this is the found type
|
||||
//[cfail2]~| NOTE this is the found type
|
||||
|
||||
pub fn consume_foo(_: Foo) {}
|
||||
//[cfail2]~^ NOTE function defined here
|
||||
|
|
@ -27,8 +27,6 @@ fn test() {
|
|||
//[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo`
|
||||
//[cfail2]~| NOTE arguments to this function are incorrect
|
||||
//[cfail2]~| NOTE function defined here
|
||||
//[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux`
|
||||
//[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux`
|
||||
|
||||
consume_foo(aux::produce_foo());
|
||||
//[cfail2]~^ ERROR mismatched types [E0308]
|
||||
|
|
|
|||
|
|
@ -7,22 +7,19 @@ error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied
|
|||
note: there are multiple different versions of crate `foo` in the dependency graph
|
||||
--> foo-current.rs:7:1
|
||||
|
|
||||
4 | extern crate foo;
|
||||
| ----------------- one version of crate `foo` used here, as a direct dependency of the current crate
|
||||
5 |
|
||||
6 | pub struct Struct;
|
||||
| ----------------- this type implements the required trait
|
||||
7 | pub trait Trait {}
|
||||
| ^^^^^^^^^^^^^^^ this is the required trait
|
||||
| ^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: foo-prev.rs:X:Y
|
||||
|
|
||||
4 | pub struct Struct;
|
||||
| ----------------- this type doesn't implement the required trait
|
||||
5 | pub trait Trait {}
|
||||
| --------------- this is the found trait
|
||||
= note: two types coming from two different versions of the same crate are different types even if they look the same
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `Trait` is implemented for `Struct`
|
||||
--> foo-current.rs:8:1
|
||||
|
|
||||
8 | impl Trait for Struct {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_trait`
|
||||
--> foo-current.rs:10:19
|
||||
|
|
||||
|
|
|
|||
|
|
@ -9,26 +9,19 @@ LL | do_something(Type);
|
|||
note: there are multiple different versions of crate `dependency` in the dependency graph
|
||||
--> replaced
|
||||
|
|
||||
LL | pub struct Type(pub i32);
|
||||
| --------------- this type implements the required trait
|
||||
LL | pub trait Trait {
|
||||
| ^^^^^^^^^^^^^^^ this is the required trait
|
||||
| ^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | extern crate dep_2_reexport;
|
||||
| ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
|
||||
LL | extern crate dependency;
|
||||
| ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub struct Type;
|
||||
| --------------- this type doesn't implement the required trait
|
||||
LL | pub trait Trait {
|
||||
| --------------- this is the found trait
|
||||
= note: two types coming from two different versions of the same crate are different types even if they look the same
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `Trait` is implemented for `dependency::Type`
|
||||
--> replaced
|
||||
|
|
||||
LL | impl Trait for Type {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `do_something`
|
||||
--> replaced
|
||||
|
|
||||
|
|
@ -45,19 +38,13 @@ note: there are multiple different versions of crate `dependency` in the depende
|
|||
--> replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| ^^^^^^^^^^^^^^^ this is the trait that is needed
|
||||
LL | fn foo(&self);
|
||||
| -------------- the method is available for `dep_2_reexport::Type` here
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | use dependency::{Trait, do_something, do_something_trait, do_something_type};
|
||||
| ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
|
||||
| ^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| --------------- this is the trait that was imported
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
|
||||
error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope
|
||||
--> replaced
|
||||
|
|
@ -69,20 +56,13 @@ note: there are multiple different versions of crate `dependency` in the depende
|
|||
--> replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| ^^^^^^^^^^^^^^^ this is the trait that is needed
|
||||
LL | fn foo(&self);
|
||||
LL | fn bar();
|
||||
| --------- the associated function is available for `dep_2_reexport::Type` here
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | use dependency::{Trait, do_something, do_something_trait, do_something_type};
|
||||
| ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
|
||||
| ^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| --------------- this is the trait that was imported
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
|
||||
error[E0277]: the trait bound `OtherType: Trait` is not satisfied
|
||||
--> replaced
|
||||
|
|
@ -96,25 +76,18 @@ note: there are multiple different versions of crate `dependency` in the depende
|
|||
--> replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| ^^^^^^^^^^^^^^^ this is the required trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | extern crate dep_2_reexport;
|
||||
| ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
|
||||
LL | extern crate dependency;
|
||||
| ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub struct OtherType;
|
||||
| -------------------- this type doesn't implement the required trait
|
||||
| ^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub trait Trait {
|
||||
| --------------- this is the found trait
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `Trait` is implemented for `dependency::Type`
|
||||
--> replaced
|
||||
|
|
||||
LL | impl Trait for Type {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `do_something`
|
||||
--> replaced
|
||||
|
|
||||
|
|
@ -129,23 +102,16 @@ LL | do_something_type(Type);
|
|||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same
|
||||
note: there are multiple different versions of crate `dependency` in the dependency graph
|
||||
--> replaced
|
||||
|
|
||||
LL | pub struct Type(pub i32);
|
||||
| ^^^^^^^^^^^^^^^ this is the expected type `dependency::Type`
|
||||
| ^^^^^^^^^^^^^^^ this is the expected type
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub struct Type;
|
||||
| ^^^^^^^^^^^^^^^ this is the found type `dep_2_reexport::Type`
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | extern crate dep_2_reexport;
|
||||
| ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
|
||||
LL | extern crate dependency;
|
||||
| ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
|
||||
| --------------- this is the found type
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
note: function defined here
|
||||
--> replaced
|
||||
|
|
@ -161,23 +127,16 @@ LL | do_something_trait(Box::new(Type) as Box<dyn Trait2>);
|
|||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same
|
||||
note: there are multiple different versions of crate `dependency` in the dependency graph
|
||||
--> replaced
|
||||
|
|
||||
LL | pub trait Trait2 {}
|
||||
| ^^^^^^^^^^^^^^^^ this is the expected trait `dependency::Trait2`
|
||||
| ^^^^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | pub trait Trait2 {}
|
||||
| ^^^^^^^^^^^^^^^^ this is the found trait `dep_2_reexport::Trait2`
|
||||
|
|
||||
::: replaced
|
||||
|
|
||||
LL | extern crate dep_2_reexport;
|
||||
| ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
|
||||
LL | extern crate dependency;
|
||||
| ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
|
||||
| ---------------- this is the found trait
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
note: function defined here
|
||||
--> replaced
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ help: item with same name found
|
|||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: perhaps two different versions of crate `foo` are being used?
|
||||
= note: there are multiple different versions of crate `foo` in the dependency graph
|
||||
= note: required for `Bar` to implement `Into<re_export_foo::foo::Foo>`
|
||||
note: required by a bound in `into_foo`
|
||||
--> $DIR/re-export-foo.rs:3:25
|
||||
|
|
|
|||
|
|
@ -32,13 +32,15 @@ fn main() {
|
|||
extern crate crate_a1 as a;
|
||||
a::try_foo(foo);
|
||||
//~^ ERROR E0277
|
||||
//~| HELP trait impl with same name found
|
||||
//~| NOTE perhaps two different versions of crate `crate_a2`
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
|
||||
// We don't want to see the "version mismatch" help message here
|
||||
// because `implements_no_traits` has no impl for `Foo`
|
||||
a::try_foo(implements_no_traits);
|
||||
//~^ ERROR E0277
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
|
||||
// We don't want to see the "version mismatch" help message here
|
||||
// because `other_variant_implements_mismatched_trait`
|
||||
|
|
@ -46,6 +48,8 @@ fn main() {
|
|||
// only for its `<usize>` variant.
|
||||
a::try_foo(other_variant_implements_mismatched_trait);
|
||||
//~^ ERROR E0277
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
|
||||
// We don't want to see the "version mismatch" help message here
|
||||
// because `ImplementsTraitForUsize` only has
|
||||
|
|
@ -53,5 +57,7 @@ fn main() {
|
|||
a::try_foo(other_variant_implements_correct_trait);
|
||||
//~^ ERROR E0277
|
||||
//~| HELP the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>`
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,17 @@ LL | a::try_foo(foo);
|
|||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: trait impl with same name found
|
||||
--> $DIR/auxiliary/crate_a2.rs:5:1
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:1:1
|
||||
|
|
||||
LL | impl Bar for Foo {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= note: perhaps two different versions of crate `crate_a2` are being used?
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a2.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ------------- this is the found trait
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>`
|
||||
--> $DIR/auxiliary/crate_a1.rs:9:1
|
||||
|
|
||||
|
|
@ -31,6 +36,17 @@ LL | a::try_foo(implements_no_traits);
|
|||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:1:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a2.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ------------- this is the trait that was imported
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>`
|
||||
--> $DIR/auxiliary/crate_a1.rs:9:1
|
||||
|
|
||||
|
|
@ -43,19 +59,24 @@ LL | pub fn try_foo(x: impl Bar) {}
|
|||
| ^^^ required by this bound in `try_foo`
|
||||
|
||||
error[E0277]: the trait bound `ImplementsWrongTraitConditionally<isize>: main::a::Bar` is not satisfied
|
||||
--> $DIR/same-crate-name.rs:47:20
|
||||
--> $DIR/same-crate-name.rs:49:20
|
||||
|
|
||||
LL | a::try_foo(other_variant_implements_mismatched_trait);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally<isize>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: trait impl with same name found
|
||||
--> $DIR/auxiliary/crate_a2.rs:13:1
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:1:1
|
||||
|
|
||||
LL | impl Bar for ImplementsWrongTraitConditionally<isize> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: perhaps two different versions of crate `crate_a2` are being used?
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a2.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ------------- this is the found trait
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>`
|
||||
--> $DIR/auxiliary/crate_a1.rs:9:1
|
||||
|
|
||||
|
|
@ -68,13 +89,24 @@ LL | pub fn try_foo(x: impl Bar) {}
|
|||
| ^^^ required by this bound in `try_foo`
|
||||
|
||||
error[E0277]: the trait bound `ImplementsTraitForUsize<isize>: main::a::Bar` is not satisfied
|
||||
--> $DIR/same-crate-name.rs:53:20
|
||||
--> $DIR/same-crate-name.rs:57:20
|
||||
|
|
||||
LL | a::try_foo(other_variant_implements_correct_trait);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize<isize>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:1:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a2.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ------------- this is the trait that was imported
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>`
|
||||
--> $DIR/auxiliary/crate_a1.rs:9:1
|
||||
|
|
||||
|
|
|
|||
28
tests/ui/traits/similarly_named_trait.rs
Normal file
28
tests/ui/traits/similarly_named_trait.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
trait Trait {} //~ HELP this trait has no implementations, consider adding one
|
||||
trait TraitWithParam<T> {} //~ HELP this trait has no implementations, consider adding one
|
||||
|
||||
mod m {
|
||||
pub trait Trait {}
|
||||
pub trait TraitWithParam<T> {}
|
||||
pub struct St; //~ HELP the trait `Trait` is not implemented for `St`
|
||||
//~| HELP the trait `TraitWithParam<St>` is not implemented for `St`
|
||||
impl Trait for St {}
|
||||
impl<T> TraitWithParam<T> for St {}
|
||||
}
|
||||
|
||||
fn func<T: Trait>(_: T) {} //~ NOTE required by a bound in `func`
|
||||
//~^ NOTE required by this bound in `func`
|
||||
|
||||
fn func2<T: TraitWithParam<T>> (_: T) {} //~ NOTE required by a bound in `func2`
|
||||
//~^ NOTE required by this bound in `func2`
|
||||
|
||||
fn main() {
|
||||
func(m::St); //~ ERROR the trait bound `St: Trait` is not satisfied
|
||||
//~^ NOTE unsatisfied trait bound
|
||||
//~| NOTE required by a bound introduced by this call
|
||||
//~| NOTE `St` implements similarly named trait `m::Trait`, but not `Trait`
|
||||
func2(m::St); //~ ERROR the trait bound `St: TraitWithParam<St>` is not satisfied
|
||||
//~^ NOTE unsatisfied trait bound
|
||||
//~| NOTE required by a bound introduced by this call
|
||||
//~| NOTE `St` implements similarly named trait `m::TraitWithParam`, but not `TraitWithParam<St>`
|
||||
}
|
||||
53
tests/ui/traits/similarly_named_trait.stderr
Normal file
53
tests/ui/traits/similarly_named_trait.stderr
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
error[E0277]: the trait bound `St: Trait` is not satisfied
|
||||
--> $DIR/similarly_named_trait.rs:20:10
|
||||
|
|
||||
LL | func(m::St);
|
||||
| ---- ^^^^^ unsatisfied trait bound
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: the trait `Trait` is not implemented for `St`
|
||||
--> $DIR/similarly_named_trait.rs:7:5
|
||||
|
|
||||
LL | pub struct St;
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: `St` implements similarly named trait `m::Trait`, but not `Trait`
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/similarly_named_trait.rs:1:1
|
||||
|
|
||||
LL | trait Trait {}
|
||||
| ^^^^^^^^^^^
|
||||
note: required by a bound in `func`
|
||||
--> $DIR/similarly_named_trait.rs:13:12
|
||||
|
|
||||
LL | fn func<T: Trait>(_: T) {}
|
||||
| ^^^^^ required by this bound in `func`
|
||||
|
||||
error[E0277]: the trait bound `St: TraitWithParam<St>` is not satisfied
|
||||
--> $DIR/similarly_named_trait.rs:24:11
|
||||
|
|
||||
LL | func2(m::St);
|
||||
| ----- ^^^^^ unsatisfied trait bound
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: the trait `TraitWithParam<St>` is not implemented for `St`
|
||||
--> $DIR/similarly_named_trait.rs:7:5
|
||||
|
|
||||
LL | pub struct St;
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: `St` implements similarly named trait `m::TraitWithParam`, but not `TraitWithParam<St>`
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/similarly_named_trait.rs:2:1
|
||||
|
|
||||
LL | trait TraitWithParam<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `func2`
|
||||
--> $DIR/similarly_named_trait.rs:16:13
|
||||
|
|
||||
LL | fn func2<T: TraitWithParam<T>> (_: T) {}
|
||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `func2`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
@ -11,24 +11,22 @@
|
|||
|
||||
fn main() {
|
||||
let foo2 = {extern crate crate_a2 as a; a::Foo};
|
||||
//~^ NOTE one type comes from crate `crate_a2` used here, which is renamed locally to `a`
|
||||
//~| NOTE one trait comes from crate `crate_a2` used here, which is renamed locally to `a`
|
||||
let bar2 = {extern crate crate_a2 as a; a::bar()};
|
||||
{
|
||||
extern crate crate_a1 as a;
|
||||
//~^ NOTE one type comes from crate `crate_a1` used here, which is renamed locally to `a`
|
||||
//~| NOTE one trait comes from crate `crate_a1` used here, which is renamed locally to `a`
|
||||
a::try_foo(foo2);
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected `main::a::Foo`, found a different `main::a::Foo`
|
||||
//~| NOTE arguments to this function are incorrect
|
||||
//~| NOTE two types coming from two different crates are different types even if they look the same
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| NOTE function defined here
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
a::try_bar(bar2);
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected trait `main::a::Bar`, found a different trait `main::a::Bar`
|
||||
//~| NOTE arguments to this function are incorrect
|
||||
//~| NOTE two types coming from two different crates are different types even if they look the same
|
||||
//~| NOTE there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
//~| NOTE function defined here
|
||||
//~| HELP you can use `cargo tree` to explore your dependency tree
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,22 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/type-mismatch-same-crate-name.rs:21:20
|
||||
--> $DIR/type-mismatch-same-crate-name.rs:17:20
|
||||
|
|
||||
LL | a::try_foo(foo2);
|
||||
| ---------- ^^^^ expected `main::a::Foo`, found a different `main::a::Foo`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: two types coming from two different crates are different types even if they look the same
|
||||
--> $DIR/auxiliary/crate_a2.rs:1:1
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:1:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^ this is the found type `crate_a2::Foo`
|
||||
| ^^^^^^^^^^^^^^ this is the expected type
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a1.rs:1:1
|
||||
::: $DIR/auxiliary/crate_a2.rs:1:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^ this is the expected type `crate_a1::Foo`
|
||||
|
|
||||
::: $DIR/type-mismatch-same-crate-name.rs:13:17
|
||||
|
|
||||
LL | let foo2 = {extern crate crate_a2 as a; a::Foo};
|
||||
| --------------------------- one type comes from crate `crate_a2` used here, which is renamed locally to `a`
|
||||
...
|
||||
LL | extern crate crate_a1 as a;
|
||||
| --------------------------- one type comes from crate `crate_a1` used here, which is renamed locally to `a`
|
||||
| -------------- this is the found type
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
note: function defined here
|
||||
--> $DIR/auxiliary/crate_a1.rs:10:8
|
||||
|
|
||||
|
|
@ -31,31 +24,24 @@ LL | pub fn try_foo(x: Foo){}
|
|||
| ^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-mismatch-same-crate-name.rs:27:20
|
||||
--> $DIR/type-mismatch-same-crate-name.rs:24:20
|
||||
|
|
||||
LL | a::try_bar(bar2);
|
||||
| ---------- ^^^^ expected trait `main::a::Bar`, found a different trait `main::a::Bar`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: two types coming from two different crates are different types even if they look the same
|
||||
--> $DIR/auxiliary/crate_a2.rs:3:1
|
||||
note: there are multiple different versions of crate `crate_a1` in the dependency graph
|
||||
--> $DIR/auxiliary/crate_a1.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the found trait `crate_a2::Bar`
|
||||
| ^^^^^^^^^^^^^ this is the expected trait
|
||||
|
|
||||
::: $DIR/auxiliary/crate_a1.rs:3:1
|
||||
::: $DIR/auxiliary/crate_a2.rs:3:1
|
||||
|
|
||||
LL | pub trait Bar {}
|
||||
| ^^^^^^^^^^^^^ this is the expected trait `crate_a1::Bar`
|
||||
|
|
||||
::: $DIR/type-mismatch-same-crate-name.rs:13:17
|
||||
|
|
||||
LL | let foo2 = {extern crate crate_a2 as a; a::Foo};
|
||||
| --------------------------- one trait comes from crate `crate_a2` used here, which is renamed locally to `a`
|
||||
...
|
||||
LL | extern crate crate_a1 as a;
|
||||
| --------------------------- one trait comes from crate `crate_a1` used here, which is renamed locally to `a`
|
||||
| ------------- this is the found trait
|
||||
= help: you can use `cargo tree` to explore your dependency tree
|
||||
note: function defined here
|
||||
--> $DIR/auxiliary/crate_a1.rs:11:8
|
||||
|
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ error[E0277]: the trait bound `T: Pointee` is not satisfied
|
|||
LL | components: PtrComponents<T>,
|
||||
| ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T`
|
||||
|
|
||||
= note: `T` implements similarly named trait `std::ptr::Pointee`, but not `Pointee`
|
||||
note: required by a bound in `PtrComponents`
|
||||
--> $DIR/issue-81199.rs:11:25
|
||||
|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue