Auto merge of #128786 - estebank:multiple-crate-versions, r=fee1-dead · rust-lang/rust@9b318d2 (original) (raw)
`@@ -3448,6 +3448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
`
3448
3448
`trait_missing_method: bool,
`
3449
3449
`) {
`
3450
3450
`let mut alt_rcvr_sugg = false;
`
``
3451
`+
let mut trait_in_other_version_found = false;
`
3451
3452
`if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
`
3452
3453
`debug!(
`
3453
3454
`"suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
`
`@@ -3489,8 +3490,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
`
3489
3490
`` // self types and rely on the suggestion to use
the trait from
``
3490
3491
`` // suggest_valid_traits
.
``
3491
3492
`let did = Some(pick.item.container_id(self.tcx));
`
3492
``
`-
let skip = skippable.contains(&did);
`
3493
``
`-
if pick.autoderefs == 0 && !skip {
`
``
3493
`+
if skippable.contains(&did) {
`
``
3494
`+
continue;
`
``
3495
`+
}
`
``
3496
`+
trait_in_other_version_found = self
`
``
3497
`+
.detect_and_explain_multiple_crate_versions(
`
``
3498
`+
err,
`
``
3499
`+
pick.item.def_id,
`
``
3500
`+
rcvr.hir_id,
`
``
3501
`+
*rcvr_ty,
`
``
3502
`+
);
`
``
3503
`+
if pick.autoderefs == 0 && !trait_in_other_version_found {
`
3494
3504
` err.span_label(
`
3495
3505
` pick.item.ident(self.tcx).span,
`
3496
3506
`` format!("the method is available for {rcvr_ty}
here"),
``
`@@ -3675,7 +3685,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
`
3675
3685
`}
`
3676
3686
`}
`
3677
3687
`}
`
3678
``
`-
if self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) {
`
``
3688
+
``
3689
`+
if let SelfSource::QPath(ty) = source
`
``
3690
`+
&& !valid_out_of_scope_traits.is_empty()
`
``
3691
`+
&& let hir::TyKind::Path(path) = ty.kind
`
``
3692
`+
&& let hir::QPath::Resolved(_, path) = path
`
``
3693
`+
&& let Some(def_id) = path.res.opt_def_id()
`
``
3694
`+
&& let Some(assoc) = self
`
``
3695
`+
.tcx
`
``
3696
`+
.associated_items(valid_out_of_scope_traits[0])
`
``
3697
`+
.filter_by_name_unhygienic(item_name.name)
`
``
3698
`+
.next()
`
``
3699
`+
{
`
``
3700
`` +
// See if the Type::function(val)
where function
wasn't found corresponds to a
``
``
3701
`` +
// Trait
that is imported directly, but Type
came from a different version of the
``
``
3702
`+
// same crate.
`
``
3703
`+
let rcvr_ty = self.tcx.type_of(def_id).instantiate_identity();
`
``
3704
`+
trait_in_other_version_found = self.detect_and_explain_multiple_crate_versions(
`
``
3705
`+
err,
`
``
3706
`+
assoc.def_id,
`
``
3707
`+
ty.hir_id,
`
``
3708
`+
rcvr_ty,
`
``
3709
`+
);
`
``
3710
`+
}
`
``
3711
`+
if !trait_in_other_version_found
`
``
3712
`+
&& self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true)
`
``
3713
`+
{
`
3679
3714
`return;
`
3680
3715
`}
`
3681
3716
``
`@@ -4040,6 +4075,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
`
4040
4075
`}
`
4041
4076
`}
`
4042
4077
``
``
4078
`+
fn detect_and_explain_multiple_crate_versions(
`
``
4079
`+
&self,
`
``
4080
`+
err: &mut Diag<'_>,
`
``
4081
`+
item_def_id: DefId,
`
``
4082
`+
hir_id: hir::HirId,
`
``
4083
`+
rcvr_ty: Ty<'_>,
`
``
4084
`+
) -> bool {
`
``
4085
`+
let hir_id = self.tcx.parent_hir_id(hir_id);
`
``
4086
`+
let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
`
``
4087
`+
if traits.is_empty() {
`
``
4088
`+
return false;
`
``
4089
`+
}
`
``
4090
`+
let trait_def_id = self.tcx.parent(item_def_id);
`
``
4091
`+
let krate = self.tcx.crate_name(trait_def_id.krate);
`
``
4092
`+
let name = self.tcx.item_name(trait_def_id);
`
``
4093
`+
let candidates: Vec<_> = traits
`
``
4094
`+
.iter()
`
``
4095
`+
.filter(|c| {
`
``
4096
`+
c.def_id.krate != trait_def_id.krate
`
``
4097
`+
&& self.tcx.crate_name(c.def_id.krate) == krate
`
``
4098
`+
&& self.tcx.item_name(c.def_id) == name
`
``
4099
`+
})
`
``
4100
`+
.map(|c| (c.def_id, c.import_ids.get(0).cloned()))
`
``
4101
`+
.collect();
`
``
4102
`+
if candidates.is_empty() {
`
``
4103
`+
return false;
`
``
4104
`+
}
`
``
4105
`+
let item_span = self.tcx.def_span(item_def_id);
`
``
4106
`+
let msg = format!(
`
``
4107
`` +
"there are multiple different versions of crate {krate}
in the dependency graph",
``
``
4108
`+
);
`
``
4109
`+
let trait_span = self.tcx.def_span(trait_def_id);
`
``
4110
`+
let mut multi_span: MultiSpan = trait_span.into();
`
``
4111
`+
multi_span.push_span_label(trait_span, format!("this is the trait that is needed"));
`
``
4112
`+
let descr = self.tcx.associated_item(item_def_id).descr();
`
``
4113
`+
multi_span
`
``
4114
`` +
.push_span_label(item_span, format!("the {descr} is available for {rcvr_ty}
here"));
``
``
4115
`+
for (def_id, import_def_id) in candidates {
`
``
4116
`+
if let Some(import_def_id) = import_def_id {
`
``
4117
`+
multi_span.push_span_label(
`
``
4118
`+
self.tcx.def_span(import_def_id),
`
``
4119
`+
format!(
`
``
4120
`` +
"{name}
imported here doesn't correspond to the right version of crate \
``
``
4121
`` +
{krate}
",
``
``
4122
`+
),
`
``
4123
`+
);
`
``
4124
`+
}
`
``
4125
`+
multi_span.push_span_label(
`
``
4126
`+
self.tcx.def_span(def_id),
`
``
4127
`+
format!("this is the trait that was imported"),
`
``
4128
`+
);
`
``
4129
`+
}
`
``
4130
`+
err.span_note(multi_span, msg);
`
``
4131
`+
true
`
``
4132
`+
}
`
``
4133
+
4043
4134
`` /// issue #102320, for unwrap_or
with closure as argument, suggest unwrap_or_else
``
4044
4135
`` /// FIXME: currently not working for suggesting map_or_else
, see #102408
``
4045
4136
`pub(crate) fn suggest_else_fn_with_closure(
`