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(

`