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:
bors 2025-11-11 21:54:08 +00:00
commit 11339a0ef5
15 changed files with 386 additions and 528 deletions

View file

@ -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`

View file

@ -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
}

View file

@ -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 {

View file

@ -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

View file

@ -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]

View file

@ -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
|

View file

@ -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

View file

@ -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

View file

@ -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
}
}

View file

@ -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
|

View 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>`
}

View 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`.

View file

@ -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
}
}

View file

@ -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
|

View file

@ -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
|