Skip to content

Commit c757267

Browse files
committedJan 3, 2023
Auto merge of #105752 - chenyukang:yukang/refactor-method-error, r=compiler-errors
Refactoring report_method_error While working on #105732, I found it's hard to follow this long function, so I tried to make it shorter. It's not easy for code reviewing, since so many lines of code changes, but only the positions are changed. Generally, I extract two sub-methods from `report_method_error`: https://github.com/rust-lang/rust/blob/397b66e77b279de5006facf87979f9ecff5c7f87/compiler/rustc_hir_typeck/src/method/suggest.rs#L117 to `note_candidates_on_method_error` And this long block: https://github.com/rust-lang/rust/blob/397b66e77b279de5006facf87979f9ecff5c7f87/compiler/rustc_hir_typeck/src/method/suggest.rs#L263 to `report_no_match_method_error`. r? `@compiler-errors`
·
1.88.01.68.0
2 parents ab10908 + 93e62a4 commit c757267

File tree

1 file changed

+913
-908
lines changed

1 file changed

+913
-908
lines changed
 

‎compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 913 additions & 908 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
102102

103103
pub fn report_method_error(
104104
&self,
105-
mut span: Span,
105+
span: Span,
106106
rcvr_ty: Ty<'tcx>,
107107
item_name: Ident,
108108
source: SelfSource<'tcx>,
@@ -114,144 +114,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
114114
return None;
115115
}
116116

117-
let report_candidates = |span: Span,
118-
err: &mut Diagnostic,
119-
sources: &mut Vec<CandidateSource>,
120-
sugg_span: Option<Span>| {
121-
sources.sort();
122-
sources.dedup();
123-
// Dynamic limit to avoid hiding just one candidate, which is silly.
124-
let limit = if sources.len() == 5 { 5 } else { 4 };
125-
126-
for (idx, source) in sources.iter().take(limit).enumerate() {
127-
match *source {
128-
CandidateSource::Impl(impl_did) => {
129-
// Provide the best span we can. Use the item, if local to crate, else
130-
// the impl, if local to crate (item may be defaulted), else nothing.
131-
let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
132-
let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
133-
self.associated_value(impl_trait_ref.def_id, item_name)
134-
}) else {
135-
continue;
136-
};
137-
138-
let note_span = if item.def_id.is_local() {
139-
Some(self.tcx.def_span(item.def_id))
140-
} else if impl_did.is_local() {
141-
Some(self.tcx.def_span(impl_did))
142-
} else {
143-
None
144-
};
145-
146-
let impl_ty = self.tcx.at(span).type_of(impl_did);
147-
148-
let insertion = match self.tcx.impl_trait_ref(impl_did) {
149-
None => String::new(),
150-
Some(trait_ref) => format!(
151-
" of the trait `{}`",
152-
self.tcx.def_path_str(trait_ref.def_id)
153-
),
154-
};
155-
156-
let (note_str, idx) = if sources.len() > 1 {
157-
(
158-
format!(
159-
"candidate #{} is defined in an impl{} for the type `{}`",
160-
idx + 1,
161-
insertion,
162-
impl_ty,
163-
),
164-
Some(idx + 1),
165-
)
166-
} else {
167-
(
168-
format!(
169-
"the candidate is defined in an impl{} for the type `{}`",
170-
insertion, impl_ty,
171-
),
172-
None,
173-
)
174-
};
175-
if let Some(note_span) = note_span {
176-
// We have a span pointing to the method. Show note with snippet.
177-
err.span_note(note_span, &note_str);
178-
} else {
179-
err.note(&note_str);
180-
}
181-
if let Some(sugg_span) = sugg_span
182-
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
183-
let path = self.tcx.def_path_str(trait_ref.def_id);
184-
185-
let ty = match item.kind {
186-
ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
187-
ty::AssocKind::Fn => self
188-
.tcx
189-
.fn_sig(item.def_id)
190-
.inputs()
191-
.skip_binder()
192-
.get(0)
193-
.filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
194-
.copied()
195-
.unwrap_or(rcvr_ty),
196-
};
197-
print_disambiguation_help(
198-
item_name,
199-
args,
200-
err,
201-
path,
202-
ty,
203-
item.kind,
204-
item.def_id,
205-
sugg_span,
206-
idx,
207-
self.tcx.sess.source_map(),
208-
item.fn_has_self_parameter,
209-
);
210-
}
211-
}
212-
CandidateSource::Trait(trait_did) => {
213-
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
214-
let item_span = self.tcx.def_span(item.def_id);
215-
let idx = if sources.len() > 1 {
216-
let msg = &format!(
217-
"candidate #{} is defined in the trait `{}`",
218-
idx + 1,
219-
self.tcx.def_path_str(trait_did)
220-
);
221-
err.span_note(item_span, msg);
222-
Some(idx + 1)
223-
} else {
224-
let msg = &format!(
225-
"the candidate is defined in the trait `{}`",
226-
self.tcx.def_path_str(trait_did)
227-
);
228-
err.span_note(item_span, msg);
229-
None
230-
};
231-
if let Some(sugg_span) = sugg_span {
232-
let path = self.tcx.def_path_str(trait_did);
233-
print_disambiguation_help(
234-
item_name,
235-
args,
236-
err,
237-
path,
238-
rcvr_ty,
239-
item.kind,
240-
item.def_id,
241-
sugg_span,
242-
idx,
243-
self.tcx.sess.source_map(),
244-
item.fn_has_self_parameter,
245-
);
246-
}
247-
}
248-
}
249-
}
250-
if sources.len() > limit {
251-
err.note(&format!("and {} others", sources.len() - limit));
252-
}
253-
};
254-
255117
let sugg_span = if let SelfSource::MethodCall(expr) = source {
256118
// Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
257119
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
@@ -260,777 +122,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
260122
};
261123

262124
match error {
263-
MethodError::NoMatch(NoMatchData {
264-
mut static_candidates,
265-
unsatisfied_predicates,
266-
out_of_scope_traits,
267-
lev_candidate,
268-
mode,
269-
}) => {
270-
let tcx = self.tcx;
271-
272-
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
273-
let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
274-
let is_method = mode == Mode::MethodCall;
275-
let item_kind = if is_method {
276-
"method"
277-
} else if rcvr_ty.is_enum() {
278-
"variant or associated item"
279-
} else {
280-
match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
281-
(Some(name), false) if name.is_lowercase() => "function or associated item",
282-
(Some(_), false) => "associated item",
283-
(Some(_), true) | (None, false) => "variant or associated item",
284-
(None, true) => "variant",
285-
}
286-
};
287-
288-
if self.suggest_wrapping_range_with_parens(
289-
tcx, rcvr_ty, source, span, item_name, &ty_str,
290-
) || self.suggest_constraining_numerical_ty(
291-
tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
292-
) {
293-
return None;
294-
}
295-
span = item_name.span;
296-
297-
// Don't show generic arguments when the method can't be found in any implementation (#81576).
298-
let mut ty_str_reported = ty_str.clone();
299-
if let ty::Adt(_, generics) = rcvr_ty.kind() {
300-
if generics.len() > 0 {
301-
let mut autoderef = self.autoderef(span, rcvr_ty);
302-
let candidate_found = autoderef.any(|(ty, _)| {
303-
if let ty::Adt(adt_def, _) = ty.kind() {
304-
self.tcx
305-
.inherent_impls(adt_def.did())
306-
.iter()
307-
.filter_map(|def_id| self.associated_value(*def_id, item_name))
308-
.count()
309-
>= 1
310-
} else {
311-
false
312-
}
313-
});
314-
let has_deref = autoderef.step_count() > 0;
315-
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
316-
if let Some((path_string, _)) = ty_str.split_once('<') {
317-
ty_str_reported = path_string.to_string();
318-
}
319-
}
320-
}
321-
}
322-
323-
let mut err = struct_span_err!(
324-
tcx.sess,
125+
MethodError::NoMatch(mut no_match_data) => {
126+
return self.report_no_match_method_error(
325127
span,
326-
E0599,
327-
"no {} named `{}` found for {} `{}` in the current scope",
328-
item_kind,
128+
rcvr_ty,
329129
item_name,
330-
rcvr_ty.prefix_string(self.tcx),
331-
ty_str_reported,
130+
source,
131+
args,
132+
sugg_span,
133+
&mut no_match_data,
332134
);
333-
if rcvr_ty.references_error() {
334-
err.downgrade_to_delayed_bug();
335-
}
336-
337-
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
338-
self.suggest_await_before_method(
339-
&mut err, item_name, rcvr_ty, cal, span,
340-
);
341-
}
342-
if let Some(span) =
343-
tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
344-
{
345-
err.span_suggestion(
346-
span.shrink_to_lo(),
347-
"you are looking for the module in `std`, not the primitive type",
348-
"std::",
349-
Applicability::MachineApplicable,
350-
);
351-
}
352-
if let ty::RawPtr(_) = &rcvr_ty.kind() {
353-
err.note(
354-
"try using `<*const T>::as_ref()` to get a reference to the \
355-
type behind the pointer: https://doc.rust-lang.org/std/\
356-
primitive.pointer.html#method.as_ref",
357-
);
358-
err.note(
359-
"using `<*const T>::as_ref()` on a pointer which is unaligned or points \
360-
to invalid or uninitialized memory is undefined behavior",
361-
);
362-
}
363-
364-
let ty_span = match rcvr_ty.kind() {
365-
ty::Param(param_type) => Some(
366-
param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
367-
),
368-
ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
369-
_ => None,
370-
};
371-
if let Some(span) = ty_span {
372-
err.span_label(
373-
span,
374-
format!(
375-
"{item_kind} `{item_name}` not found for this {}",
376-
rcvr_ty.prefix_string(self.tcx)
377-
),
378-
);
379-
}
380-
381-
if let SelfSource::MethodCall(rcvr_expr) = source {
382-
self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
383-
let call_expr = self
384-
.tcx
385-
.hir()
386-
.expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
387-
let probe = self.lookup_probe(
388-
item_name,
389-
output_ty,
390-
call_expr,
391-
ProbeScope::AllTraits,
392-
);
393-
probe.is_ok()
394-
});
395-
}
396-
397-
let mut custom_span_label = false;
398-
399-
if !static_candidates.is_empty() {
400-
err.note(
401-
"found the following associated functions; to be used as methods, \
402-
functions must have a `self` parameter",
403-
);
404-
err.span_label(span, "this is an associated function, not a method");
405-
custom_span_label = true;
406-
}
407-
if static_candidates.len() == 1 {
408-
self.suggest_associated_call_syntax(
409-
&mut err,
410-
&static_candidates,
411-
rcvr_ty,
412-
source,
413-
item_name,
414-
args,
415-
sugg_span,
416-
);
417-
418-
report_candidates(span, &mut err, &mut static_candidates, None);
419-
} else if static_candidates.len() > 1 {
420-
report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
421-
}
422-
423-
let mut bound_spans = vec![];
424-
let mut restrict_type_params = false;
425-
let mut unsatisfied_bounds = false;
426-
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
427-
let msg = "consider using `len` instead";
428-
if let SelfSource::MethodCall(_expr) = source {
429-
err.span_suggestion_short(
430-
span,
431-
msg,
432-
"len",
433-
Applicability::MachineApplicable,
434-
);
435-
} else {
436-
err.span_label(span, msg);
437-
}
438-
if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
439-
let iterator_trait = self.tcx.def_path_str(iterator_trait);
440-
err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
441-
}
442-
} else if !unsatisfied_predicates.is_empty() {
443-
let mut type_params = FxHashMap::default();
444-
445-
// Pick out the list of unimplemented traits on the receiver.
446-
// This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
447-
let mut unimplemented_traits = FxHashMap::default();
448-
let mut unimplemented_traits_only = true;
449-
for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
450-
if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
451-
(predicate.kind().skip_binder(), cause.as_ref())
452-
{
453-
if p.trait_ref.self_ty() != rcvr_ty {
454-
// This is necessary, not just to keep the errors clean, but also
455-
// because our derived obligations can wind up with a trait ref that
456-
// requires a different param_env to be correctly compared.
457-
continue;
458-
}
459-
unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
460-
predicate.kind().rebind(p.trait_ref),
461-
Obligation {
462-
cause: cause.clone(),
463-
param_env: self.param_env,
464-
predicate: *predicate,
465-
recursion_depth: 0,
466-
},
467-
));
468-
}
469-
}
470-
471-
// Make sure that, if any traits other than the found ones were involved,
472-
// we don't don't report an unimplemented trait.
473-
// We don't want to say that `iter::Cloned` is not an iterator, just
474-
// because of some non-Clone item being iterated over.
475-
for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
476-
match predicate.kind().skip_binder() {
477-
ty::PredicateKind::Clause(ty::Clause::Trait(p))
478-
if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
479-
_ => {
480-
unimplemented_traits_only = false;
481-
break;
482-
}
483-
}
484-
}
485-
486-
let mut collect_type_param_suggestions =
487-
|self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
488-
// We don't care about regions here, so it's fine to skip the binder here.
489-
if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
490-
(self_ty.kind(), parent_pred.kind().skip_binder())
491-
{
492-
let hir = self.tcx.hir();
493-
let node = match p.trait_ref.self_ty().kind() {
494-
ty::Param(_) => {
495-
// Account for `fn` items like in `issue-35677.rs` to
496-
// suggest restricting its type params.
497-
let parent_body =
498-
hir.body_owner(hir::BodyId { hir_id: self.body_id });
499-
Some(hir.get(parent_body))
500-
}
501-
ty::Adt(def, _) => {
502-
def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
503-
}
504-
_ => None,
505-
};
506-
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
507-
if let Some(g) = kind.generics() {
508-
let key = (
509-
g.tail_span_for_predicate_suggestion(),
510-
g.add_where_or_trailing_comma(),
511-
);
512-
type_params
513-
.entry(key)
514-
.or_insert_with(FxHashSet::default)
515-
.insert(obligation.to_owned());
516-
}
517-
}
518-
}
519-
};
520-
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
521-
let msg = format!(
522-
"doesn't satisfy `{}`",
523-
if obligation.len() > 50 { quiet } else { obligation }
524-
);
525-
match &self_ty.kind() {
526-
// Point at the type that couldn't satisfy the bound.
527-
ty::Adt(def, _) => {
528-
bound_spans.push((self.tcx.def_span(def.did()), msg))
529-
}
530-
// Point at the trait object that couldn't satisfy the bound.
531-
ty::Dynamic(preds, _, _) => {
532-
for pred in preds.iter() {
533-
match pred.skip_binder() {
534-
ty::ExistentialPredicate::Trait(tr) => bound_spans
535-
.push((self.tcx.def_span(tr.def_id), msg.clone())),
536-
ty::ExistentialPredicate::Projection(_)
537-
| ty::ExistentialPredicate::AutoTrait(_) => {}
538-
}
539-
}
540-
}
541-
// Point at the closure that couldn't satisfy the bound.
542-
ty::Closure(def_id, _) => bound_spans.push((
543-
tcx.def_span(*def_id),
544-
format!("doesn't satisfy `{}`", quiet),
545-
)),
546-
_ => {}
547-
}
548-
};
549-
let mut format_pred = |pred: ty::Predicate<'tcx>| {
550-
let bound_predicate = pred.kind();
551-
match bound_predicate.skip_binder() {
552-
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
553-
let pred = bound_predicate.rebind(pred);
554-
// `<Foo as Iterator>::Item = String`.
555-
let projection_ty = pred.skip_binder().projection_ty;
556-
557-
let substs_with_infer_self = tcx.mk_substs(
558-
iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
559-
.chain(projection_ty.substs.iter().skip(1)),
560-
);
561-
562-
let quiet_projection_ty =
563-
tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
564-
565-
let term = pred.skip_binder().term;
566-
567-
let obligation = format!("{} = {}", projection_ty, term);
568-
let quiet = with_forced_trimmed_paths!(format!(
569-
"{} = {}",
570-
quiet_projection_ty, term
571-
));
572-
573-
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
574-
Some((obligation, projection_ty.self_ty()))
575-
}
576-
ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
577-
let p = poly_trait_ref.trait_ref;
578-
let self_ty = p.self_ty();
579-
let path = p.print_only_trait_path();
580-
let obligation = format!("{}: {}", self_ty, path);
581-
let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
582-
bound_span_label(self_ty, &obligation, &quiet);
583-
Some((obligation, self_ty))
584-
}
585-
_ => None,
586-
}
587-
};
588-
589-
// Find all the requirements that come from a local `impl` block.
590-
let mut skip_list: FxHashSet<_> = Default::default();
591-
let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
592-
for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
593-
.iter()
594-
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
595-
.filter_map(|(p, parent, c)| match c.code() {
596-
ObligationCauseCode::ImplDerivedObligation(data) => {
597-
Some((&data.derived, p, parent, data.impl_def_id, data))
598-
}
599-
_ => None,
600-
})
601-
{
602-
let parent_trait_ref = data.parent_trait_pred;
603-
let path = parent_trait_ref.print_modifiers_and_trait_path();
604-
let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
605-
let unsatisfied_msg = "unsatisfied trait bound introduced here";
606-
let derive_msg =
607-
"unsatisfied trait bound introduced in this `derive` macro";
608-
match self.tcx.hir().get_if_local(impl_def_id) {
609-
// Unmet obligation comes from a `derive` macro, point at it once to
610-
// avoid multiple span labels pointing at the same place.
611-
Some(Node::Item(hir::Item {
612-
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
613-
..
614-
})) if matches!(
615-
self_ty.span.ctxt().outer_expn_data().kind,
616-
ExpnKind::Macro(MacroKind::Derive, _)
617-
) || matches!(
618-
of_trait.as_ref().map(|t| t
619-
.path
620-
.span
621-
.ctxt()
622-
.outer_expn_data()
623-
.kind),
624-
Some(ExpnKind::Macro(MacroKind::Derive, _))
625-
) =>
626-
{
627-
let span = self_ty.span.ctxt().outer_expn_data().call_site;
628-
let mut spans: MultiSpan = span.into();
629-
spans.push_span_label(span, derive_msg);
630-
let entry = spanned_predicates.entry(spans);
631-
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
632-
}
633-
634-
// Unmet obligation coming from an `impl`.
635-
Some(Node::Item(hir::Item {
636-
kind:
637-
hir::ItemKind::Impl(hir::Impl {
638-
of_trait, self_ty, generics, ..
639-
}),
640-
span: item_span,
641-
..
642-
})) => {
643-
let sized_pred =
644-
unsatisfied_predicates.iter().any(|(pred, _, _)| {
645-
match pred.kind().skip_binder() {
646-
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
647-
Some(pred.def_id())
648-
== self.tcx.lang_items().sized_trait()
649-
&& pred.polarity == ty::ImplPolarity::Positive
650-
}
651-
_ => false,
652-
}
653-
});
654-
for param in generics.params {
655-
if param.span == cause.span && sized_pred {
656-
let (sp, sugg) = match param.colon_span {
657-
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
658-
None => (param.span.shrink_to_hi(), ": ?Sized"),
659-
};
660-
err.span_suggestion_verbose(
661-
sp,
662-
"consider relaxing the type parameter's implicit \
663-
`Sized` bound",
664-
sugg,
665-
Applicability::MachineApplicable,
666-
);
667-
}
668-
}
669-
if let Some(pred) = parent_p {
670-
// Done to add the "doesn't satisfy" `span_label`.
671-
let _ = format_pred(*pred);
672-
}
673-
skip_list.insert(p);
674-
let mut spans = if cause.span != *item_span {
675-
let mut spans: MultiSpan = cause.span.into();
676-
spans.push_span_label(cause.span, unsatisfied_msg);
677-
spans
678-
} else {
679-
let mut spans = Vec::with_capacity(2);
680-
if let Some(trait_ref) = of_trait {
681-
spans.push(trait_ref.path.span);
682-
}
683-
spans.push(self_ty.span);
684-
spans.into()
685-
};
686-
if let Some(trait_ref) = of_trait {
687-
spans.push_span_label(trait_ref.path.span, "");
688-
}
689-
spans.push_span_label(self_ty.span, "");
690-
691-
let entry = spanned_predicates.entry(spans);
692-
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
693-
}
694-
Some(Node::Item(hir::Item {
695-
kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
696-
span: item_span,
697-
..
698-
})) => {
699-
tcx.sess.delay_span_bug(
700-
*item_span,
701-
"auto trait is invoked with no method error, but no error reported?",
702-
);
703-
}
704-
Some(_) => unreachable!(),
705-
None => (),
706-
}
707-
}
708-
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
709-
spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
710-
for (span, (_path, _self_ty, preds)) in spanned_predicates {
711-
let mut preds: Vec<_> = preds
712-
.into_iter()
713-
.filter_map(|pred| format_pred(*pred))
714-
.map(|(p, _)| format!("`{}`", p))
715-
.collect();
716-
preds.sort();
717-
preds.dedup();
718-
let msg = if let [pred] = &preds[..] {
719-
format!("trait bound {} was not satisfied", pred)
720-
} else {
721-
format!(
722-
"the following trait bounds were not satisfied:\n{}",
723-
preds.join("\n"),
724-
)
725-
};
726-
err.span_note(span, &msg);
727-
unsatisfied_bounds = true;
728-
}
729-
730-
// The requirements that didn't have an `impl` span to show.
731-
let mut bound_list = unsatisfied_predicates
732-
.iter()
733-
.filter_map(|(pred, parent_pred, _cause)| {
734-
format_pred(*pred).map(|(p, self_ty)| {
735-
collect_type_param_suggestions(self_ty, *pred, &p);
736-
(
737-
match parent_pred {
738-
None => format!("`{}`", &p),
739-
Some(parent_pred) => match format_pred(*parent_pred) {
740-
None => format!("`{}`", &p),
741-
Some((parent_p, _)) => {
742-
collect_type_param_suggestions(
743-
self_ty,
744-
*parent_pred,
745-
&p,
746-
);
747-
format!(
748-
"`{}`\nwhich is required by `{}`",
749-
p, parent_p
750-
)
751-
}
752-
},
753-
},
754-
*pred,
755-
)
756-
})
757-
})
758-
.filter(|(_, pred)| !skip_list.contains(&pred))
759-
.map(|(t, _)| t)
760-
.enumerate()
761-
.collect::<Vec<(usize, String)>>();
762-
763-
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
764-
restrict_type_params = true;
765-
// #74886: Sort here so that the output is always the same.
766-
let mut obligations = obligations.into_iter().collect::<Vec<_>>();
767-
obligations.sort();
768-
err.span_suggestion_verbose(
769-
span,
770-
&format!(
771-
"consider restricting the type parameter{s} to satisfy the \
772-
trait bound{s}",
773-
s = pluralize!(obligations.len())
774-
),
775-
format!("{} {}", add_where_or_comma, obligations.join(", ")),
776-
Applicability::MaybeIncorrect,
777-
);
778-
}
779-
780-
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
781-
bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
782-
bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
783-
784-
if !bound_list.is_empty() || !skip_list.is_empty() {
785-
let bound_list = bound_list
786-
.into_iter()
787-
.map(|(_, path)| path)
788-
.collect::<Vec<_>>()
789-
.join("\n");
790-
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
791-
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
792-
let (primary_message, label) =
793-
if unimplemented_traits.len() == 1 && unimplemented_traits_only {
794-
unimplemented_traits
795-
.into_iter()
796-
.next()
797-
.map(|(_, (trait_ref, obligation))| {
798-
if trait_ref.self_ty().references_error()
799-
|| rcvr_ty.references_error()
800-
{
801-
// Avoid crashing.
802-
return (None, None);
803-
}
804-
let OnUnimplementedNote { message, label, .. } = self
805-
.err_ctxt()
806-
.on_unimplemented_note(trait_ref, &obligation);
807-
(message, label)
808-
})
809-
.unwrap()
810-
} else {
811-
(None, None)
812-
};
813-
let primary_message = primary_message.unwrap_or_else(|| format!(
814-
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
815-
but its trait bounds were not satisfied"
816-
));
817-
err.set_primary_message(&primary_message);
818-
if let Some(label) = label {
819-
custom_span_label = true;
820-
err.span_label(span, label);
821-
}
822-
if !bound_list.is_empty() {
823-
err.note(&format!(
824-
"the following trait bounds were not satisfied:\n{bound_list}"
825-
));
826-
}
827-
self.suggest_derive(&mut err, &unsatisfied_predicates);
828-
829-
unsatisfied_bounds = true;
830-
}
831-
}
832-
833-
let label_span_not_found = |err: &mut Diagnostic| {
834-
if unsatisfied_predicates.is_empty() {
835-
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
836-
let is_string_or_ref_str = match rcvr_ty.kind() {
837-
ty::Ref(_, ty, _) => {
838-
ty.is_str()
839-
|| matches!(
840-
ty.kind(),
841-
ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
842-
)
843-
}
844-
ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
845-
_ => false,
846-
};
847-
if is_string_or_ref_str && item_name.name == sym::iter {
848-
err.span_suggestion_verbose(
849-
item_name.span,
850-
"because of the in-memory representation of `&str`, to obtain \
851-
an `Iterator` over each of its codepoint use method `chars`",
852-
"chars",
853-
Applicability::MachineApplicable,
854-
);
855-
}
856-
if let ty::Adt(adt, _) = rcvr_ty.kind() {
857-
let mut inherent_impls_candidate = self
858-
.tcx
859-
.inherent_impls(adt.did())
860-
.iter()
861-
.copied()
862-
.filter(|def_id| {
863-
if let Some(assoc) = self.associated_value(*def_id, item_name) {
864-
// Check for both mode is the same so we avoid suggesting
865-
// incorrect associated item.
866-
match (mode, assoc.fn_has_self_parameter, source) {
867-
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
868-
// We check that the suggest type is actually
869-
// different from the received one
870-
// So we avoid suggestion method with Box<Self>
871-
// for instance
872-
self.tcx.at(span).type_of(*def_id) != rcvr_ty
873-
&& self.tcx.at(span).type_of(*def_id) != rcvr_ty
874-
}
875-
(Mode::Path, false, _) => true,
876-
_ => false,
877-
}
878-
} else {
879-
false
880-
}
881-
})
882-
.collect::<Vec<_>>();
883-
if !inherent_impls_candidate.is_empty() {
884-
inherent_impls_candidate.sort();
885-
inherent_impls_candidate.dedup();
886-
887-
// number of type to shows at most.
888-
let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
889-
let type_candidates = inherent_impls_candidate
890-
.iter()
891-
.take(limit)
892-
.map(|impl_item| {
893-
format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
894-
})
895-
.collect::<Vec<_>>()
896-
.join("\n");
897-
let additional_types = if inherent_impls_candidate.len() > limit {
898-
format!(
899-
"\nand {} more types",
900-
inherent_impls_candidate.len() - limit
901-
)
902-
} else {
903-
"".to_string()
904-
};
905-
err.note(&format!(
906-
"the {item_kind} was found for\n{}{}",
907-
type_candidates, additional_types
908-
));
909-
}
910-
}
911-
} else {
912-
let ty_str = if ty_str.len() > 50 {
913-
String::new()
914-
} else {
915-
format!("on `{ty_str}` ")
916-
};
917-
err.span_label(span, format!(
918-
"{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
919-
));
920-
}
921-
};
922-
923-
// If the method name is the name of a field with a function or closure type,
924-
// give a helping note that it has to be called as `(x.f)(...)`.
925-
if let SelfSource::MethodCall(expr) = source {
926-
if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
927-
&& lev_candidate.is_none()
928-
&& !custom_span_label
929-
{
930-
label_span_not_found(&mut err);
931-
}
932-
} else if !custom_span_label {
933-
label_span_not_found(&mut err);
934-
}
935-
936-
// Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
937-
// can't be called due to `typeof(expr): Clone` not holding.
938-
if unsatisfied_predicates.is_empty() {
939-
self.suggest_calling_method_on_field(
940-
&mut err, source, span, rcvr_ty, item_name,
941-
);
942-
}
943-
944-
self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
945-
946-
bound_spans.sort();
947-
bound_spans.dedup();
948-
for (span, msg) in bound_spans.into_iter() {
949-
err.span_label(span, &msg);
950-
}
951-
952-
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
953-
} else {
954-
self.suggest_traits_to_import(
955-
&mut err,
956-
span,
957-
rcvr_ty,
958-
item_name,
959-
args.map(|(_, args)| args.len() + 1),
960-
source,
961-
out_of_scope_traits,
962-
&unsatisfied_predicates,
963-
&static_candidates,
964-
unsatisfied_bounds,
965-
);
966-
}
967-
968-
// Don't emit a suggestion if we found an actual method
969-
// that had unsatisfied trait bounds
970-
if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
971-
let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
972-
if let Some(suggestion) = lev_distance::find_best_match_for_name(
973-
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
974-
item_name.name,
975-
None,
976-
) {
977-
err.span_suggestion(
978-
span,
979-
"there is a variant with a similar name",
980-
suggestion,
981-
Applicability::MaybeIncorrect,
982-
);
983-
}
984-
}
985-
986-
if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
987-
let msg = "remove this method call";
988-
let mut fallback_span = true;
989-
if let SelfSource::MethodCall(expr) = source {
990-
let call_expr =
991-
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
992-
if let Some(span) = call_expr.span.trim_start(expr.span) {
993-
err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
994-
fallback_span = false;
995-
}
996-
}
997-
if fallback_span {
998-
err.span_label(span, msg);
999-
}
1000-
} else if let Some(lev_candidate) = lev_candidate {
1001-
// Don't emit a suggestion if we found an actual method
1002-
// that had unsatisfied trait bounds
1003-
if unsatisfied_predicates.is_empty() {
1004-
let def_kind = lev_candidate.kind.as_def_kind();
1005-
// Methods are defined within the context of a struct and their first parameter is always self,
1006-
// which represents the instance of the struct the method is being called on
1007-
// Associated functions don’t take self as a parameter and
1008-
// they are not methods because they don’t have an instance of the struct to work with.
1009-
if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
1010-
err.span_suggestion(
1011-
span,
1012-
"there is a method with a similar name",
1013-
lev_candidate.name,
1014-
Applicability::MaybeIncorrect,
1015-
);
1016-
} else {
1017-
err.span_suggestion(
1018-
span,
1019-
&format!(
1020-
"there is {} {} with a similar name",
1021-
def_kind.article(),
1022-
def_kind.descr(lev_candidate.def_id),
1023-
),
1024-
lev_candidate.name,
1025-
Applicability::MaybeIncorrect,
1026-
);
1027-
}
1028-
}
1029-
}
1030-
1031-
self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
1032-
1033-
return Some(err);
1034135
}
1035136

1036137
MethodError::Ambiguity(mut sources) => {
@@ -1042,7 +143,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1042143
);
1043144
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
1044145

1045-
report_candidates(span, &mut err, &mut sources, Some(sugg_span));
146+
self.note_candidates_on_method_error(
147+
rcvr_ty,
148+
item_name,
149+
args,
150+
span,
151+
&mut err,
152+
&mut sources,
153+
Some(sugg_span),
154+
);
1046155
err.emit();
1047156
}
1048157

@@ -1099,6 +208,902 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1099208
None
1100209
}
1101210

211+
pub fn report_no_match_method_error(
212+
&self,
213+
mut span: Span,
214+
rcvr_ty: Ty<'tcx>,
215+
item_name: Ident,
216+
source: SelfSource<'tcx>,
217+
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
218+
sugg_span: Span,
219+
no_match_data: &mut NoMatchData<'tcx>,
220+
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
221+
let mode = no_match_data.mode;
222+
let tcx = self.tcx;
223+
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
224+
let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
225+
let is_method = mode == Mode::MethodCall;
226+
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
227+
let lev_candidate = no_match_data.lev_candidate;
228+
let item_kind = if is_method {
229+
"method"
230+
} else if rcvr_ty.is_enum() {
231+
"variant or associated item"
232+
} else {
233+
match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
234+
(Some(name), false) if name.is_lowercase() => "function or associated item",
235+
(Some(_), false) => "associated item",
236+
(Some(_), true) | (None, false) => "variant or associated item",
237+
(None, true) => "variant",
238+
}
239+
};
240+
241+
if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
242+
|| self.suggest_constraining_numerical_ty(
243+
tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
244+
)
245+
{
246+
return None;
247+
}
248+
span = item_name.span;
249+
250+
// Don't show generic arguments when the method can't be found in any implementation (#81576).
251+
let mut ty_str_reported = ty_str.clone();
252+
if let ty::Adt(_, generics) = rcvr_ty.kind() {
253+
if generics.len() > 0 {
254+
let mut autoderef = self.autoderef(span, rcvr_ty);
255+
let candidate_found = autoderef.any(|(ty, _)| {
256+
if let ty::Adt(adt_def, _) = ty.kind() {
257+
self.tcx
258+
.inherent_impls(adt_def.did())
259+
.iter()
260+
.filter_map(|def_id| self.associated_value(*def_id, item_name))
261+
.count()
262+
>= 1
263+
} else {
264+
false
265+
}
266+
});
267+
let has_deref = autoderef.step_count() > 0;
268+
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
269+
if let Some((path_string, _)) = ty_str.split_once('<') {
270+
ty_str_reported = path_string.to_string();
271+
}
272+
}
273+
}
274+
}
275+
276+
let mut err = struct_span_err!(
277+
tcx.sess,
278+
span,
279+
E0599,
280+
"no {} named `{}` found for {} `{}` in the current scope",
281+
item_kind,
282+
item_name,
283+
rcvr_ty.prefix_string(self.tcx),
284+
ty_str_reported,
285+
);
286+
if rcvr_ty.references_error() {
287+
err.downgrade_to_delayed_bug();
288+
}
289+
290+
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
291+
self.suggest_await_before_method(
292+
&mut err, item_name, rcvr_ty, cal, span,
293+
);
294+
}
295+
if let Some(span) =
296+
tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
297+
{
298+
err.span_suggestion(
299+
span.shrink_to_lo(),
300+
"you are looking for the module in `std`, not the primitive type",
301+
"std::",
302+
Applicability::MachineApplicable,
303+
);
304+
}
305+
if let ty::RawPtr(_) = &rcvr_ty.kind() {
306+
err.note(
307+
"try using `<*const T>::as_ref()` to get a reference to the \
308+
type behind the pointer: https://doc.rust-lang.org/std/\
309+
primitive.pointer.html#method.as_ref",
310+
);
311+
err.note(
312+
"using `<*const T>::as_ref()` on a pointer which is unaligned or points \
313+
to invalid or uninitialized memory is undefined behavior",
314+
);
315+
}
316+
317+
let ty_span = match rcvr_ty.kind() {
318+
ty::Param(param_type) => {
319+
Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
320+
}
321+
ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
322+
_ => None,
323+
};
324+
if let Some(span) = ty_span {
325+
err.span_label(
326+
span,
327+
format!(
328+
"{item_kind} `{item_name}` not found for this {}",
329+
rcvr_ty.prefix_string(self.tcx)
330+
),
331+
);
332+
}
333+
334+
if let SelfSource::MethodCall(rcvr_expr) = source {
335+
self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
336+
let call_expr =
337+
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
338+
let probe =
339+
self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
340+
probe.is_ok()
341+
});
342+
}
343+
344+
let mut custom_span_label = false;
345+
346+
let static_candidates = &mut no_match_data.static_candidates;
347+
if !static_candidates.is_empty() {
348+
err.note(
349+
"found the following associated functions; to be used as methods, \
350+
functions must have a `self` parameter",
351+
);
352+
err.span_label(span, "this is an associated function, not a method");
353+
custom_span_label = true;
354+
}
355+
if static_candidates.len() == 1 {
356+
self.suggest_associated_call_syntax(
357+
&mut err,
358+
&static_candidates,
359+
rcvr_ty,
360+
source,
361+
item_name,
362+
args,
363+
sugg_span,
364+
);
365+
366+
self.note_candidates_on_method_error(
367+
rcvr_ty,
368+
item_name,
369+
args,
370+
span,
371+
&mut err,
372+
static_candidates,
373+
None,
374+
);
375+
} else if static_candidates.len() > 1 {
376+
self.note_candidates_on_method_error(
377+
rcvr_ty,
378+
item_name,
379+
args,
380+
span,
381+
&mut err,
382+
static_candidates,
383+
Some(sugg_span),
384+
);
385+
}
386+
387+
let mut bound_spans = vec![];
388+
let mut restrict_type_params = false;
389+
let mut unsatisfied_bounds = false;
390+
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
391+
let msg = "consider using `len` instead";
392+
if let SelfSource::MethodCall(_expr) = source {
393+
err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
394+
} else {
395+
err.span_label(span, msg);
396+
}
397+
if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
398+
let iterator_trait = self.tcx.def_path_str(iterator_trait);
399+
err.note(&format!(
400+
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
401+
));
402+
}
403+
} else if !unsatisfied_predicates.is_empty() {
404+
let mut type_params = FxHashMap::default();
405+
406+
// Pick out the list of unimplemented traits on the receiver.
407+
// This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
408+
let mut unimplemented_traits = FxHashMap::default();
409+
let mut unimplemented_traits_only = true;
410+
for (predicate, _parent_pred, cause) in unsatisfied_predicates {
411+
if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
412+
(predicate.kind().skip_binder(), cause.as_ref())
413+
{
414+
if p.trait_ref.self_ty() != rcvr_ty {
415+
// This is necessary, not just to keep the errors clean, but also
416+
// because our derived obligations can wind up with a trait ref that
417+
// requires a different param_env to be correctly compared.
418+
continue;
419+
}
420+
unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
421+
predicate.kind().rebind(p.trait_ref),
422+
Obligation {
423+
cause: cause.clone(),
424+
param_env: self.param_env,
425+
predicate: *predicate,
426+
recursion_depth: 0,
427+
},
428+
));
429+
}
430+
}
431+
432+
// Make sure that, if any traits other than the found ones were involved,
433+
// we don't don't report an unimplemented trait.
434+
// We don't want to say that `iter::Cloned` is not an iterator, just
435+
// because of some non-Clone item being iterated over.
436+
for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
437+
match predicate.kind().skip_binder() {
438+
ty::PredicateKind::Clause(ty::Clause::Trait(p))
439+
if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
440+
_ => {
441+
unimplemented_traits_only = false;
442+
break;
443+
}
444+
}
445+
}
446+
447+
let mut collect_type_param_suggestions =
448+
|self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
449+
// We don't care about regions here, so it's fine to skip the binder here.
450+
if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
451+
(self_ty.kind(), parent_pred.kind().skip_binder())
452+
{
453+
let hir = self.tcx.hir();
454+
let node = match p.trait_ref.self_ty().kind() {
455+
ty::Param(_) => {
456+
// Account for `fn` items like in `issue-35677.rs` to
457+
// suggest restricting its type params.
458+
let parent_body =
459+
hir.body_owner(hir::BodyId { hir_id: self.body_id });
460+
Some(hir.get(parent_body))
461+
}
462+
ty::Adt(def, _) => {
463+
def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
464+
}
465+
_ => None,
466+
};
467+
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
468+
if let Some(g) = kind.generics() {
469+
let key = (
470+
g.tail_span_for_predicate_suggestion(),
471+
g.add_where_or_trailing_comma(),
472+
);
473+
type_params
474+
.entry(key)
475+
.or_insert_with(FxHashSet::default)
476+
.insert(obligation.to_owned());
477+
}
478+
}
479+
}
480+
};
481+
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
482+
let msg = format!(
483+
"doesn't satisfy `{}`",
484+
if obligation.len() > 50 { quiet } else { obligation }
485+
);
486+
match &self_ty.kind() {
487+
// Point at the type that couldn't satisfy the bound.
488+
ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
489+
// Point at the trait object that couldn't satisfy the bound.
490+
ty::Dynamic(preds, _, _) => {
491+
for pred in preds.iter() {
492+
match pred.skip_binder() {
493+
ty::ExistentialPredicate::Trait(tr) => {
494+
bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
495+
}
496+
ty::ExistentialPredicate::Projection(_)
497+
| ty::ExistentialPredicate::AutoTrait(_) => {}
498+
}
499+
}
500+
}
501+
// Point at the closure that couldn't satisfy the bound.
502+
ty::Closure(def_id, _) => bound_spans
503+
.push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
504+
_ => {}
505+
}
506+
};
507+
let mut format_pred = |pred: ty::Predicate<'tcx>| {
508+
let bound_predicate = pred.kind();
509+
match bound_predicate.skip_binder() {
510+
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
511+
let pred = bound_predicate.rebind(pred);
512+
// `<Foo as Iterator>::Item = String`.
513+
let projection_ty = pred.skip_binder().projection_ty;
514+
515+
let substs_with_infer_self = tcx.mk_substs(
516+
iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
517+
.chain(projection_ty.substs.iter().skip(1)),
518+
);
519+
520+
let quiet_projection_ty =
521+
tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
522+
523+
let term = pred.skip_binder().term;
524+
525+
let obligation = format!("{} = {}", projection_ty, term);
526+
let quiet = with_forced_trimmed_paths!(format!(
527+
"{} = {}",
528+
quiet_projection_ty, term
529+
));
530+
531+
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
532+
Some((obligation, projection_ty.self_ty()))
533+
}
534+
ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
535+
let p = poly_trait_ref.trait_ref;
536+
let self_ty = p.self_ty();
537+
let path = p.print_only_trait_path();
538+
let obligation = format!("{}: {}", self_ty, path);
539+
let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
540+
bound_span_label(self_ty, &obligation, &quiet);
541+
Some((obligation, self_ty))
542+
}
543+
_ => None,
544+
}
545+
};
546+
547+
// Find all the requirements that come from a local `impl` block.
548+
let mut skip_list: FxHashSet<_> = Default::default();
549+
let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
550+
for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
551+
.iter()
552+
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
553+
.filter_map(|(p, parent, c)| match c.code() {
554+
ObligationCauseCode::ImplDerivedObligation(data) => {
555+
Some((&data.derived, p, parent, data.impl_def_id, data))
556+
}
557+
_ => None,
558+
})
559+
{
560+
let parent_trait_ref = data.parent_trait_pred;
561+
let path = parent_trait_ref.print_modifiers_and_trait_path();
562+
let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
563+
let unsatisfied_msg = "unsatisfied trait bound introduced here";
564+
let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
565+
match self.tcx.hir().get_if_local(impl_def_id) {
566+
// Unmet obligation comes from a `derive` macro, point at it once to
567+
// avoid multiple span labels pointing at the same place.
568+
Some(Node::Item(hir::Item {
569+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
570+
..
571+
})) if matches!(
572+
self_ty.span.ctxt().outer_expn_data().kind,
573+
ExpnKind::Macro(MacroKind::Derive, _)
574+
) || matches!(
575+
of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
576+
Some(ExpnKind::Macro(MacroKind::Derive, _))
577+
) =>
578+
{
579+
let span = self_ty.span.ctxt().outer_expn_data().call_site;
580+
let mut spans: MultiSpan = span.into();
581+
spans.push_span_label(span, derive_msg);
582+
let entry = spanned_predicates.entry(spans);
583+
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
584+
}
585+
586+
// Unmet obligation coming from an `impl`.
587+
Some(Node::Item(hir::Item {
588+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
589+
span: item_span,
590+
..
591+
})) => {
592+
let sized_pred =
593+
unsatisfied_predicates.iter().any(|(pred, _, _)| {
594+
match pred.kind().skip_binder() {
595+
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
596+
Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
597+
&& pred.polarity == ty::ImplPolarity::Positive
598+
}
599+
_ => false,
600+
}
601+
});
602+
for param in generics.params {
603+
if param.span == cause.span && sized_pred {
604+
let (sp, sugg) = match param.colon_span {
605+
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
606+
None => (param.span.shrink_to_hi(), ": ?Sized"),
607+
};
608+
err.span_suggestion_verbose(
609+
sp,
610+
"consider relaxing the type parameter's implicit \
611+
`Sized` bound",
612+
sugg,
613+
Applicability::MachineApplicable,
614+
);
615+
}
616+
}
617+
if let Some(pred) = parent_p {
618+
// Done to add the "doesn't satisfy" `span_label`.
619+
let _ = format_pred(*pred);
620+
}
621+
skip_list.insert(p);
622+
let mut spans = if cause.span != *item_span {
623+
let mut spans: MultiSpan = cause.span.into();
624+
spans.push_span_label(cause.span, unsatisfied_msg);
625+
spans
626+
} else {
627+
let mut spans = Vec::with_capacity(2);
628+
if let Some(trait_ref) = of_trait {
629+
spans.push(trait_ref.path.span);
630+
}
631+
spans.push(self_ty.span);
632+
spans.into()
633+
};
634+
if let Some(trait_ref) = of_trait {
635+
spans.push_span_label(trait_ref.path.span, "");
636+
}
637+
spans.push_span_label(self_ty.span, "");
638+
639+
let entry = spanned_predicates.entry(spans);
640+
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
641+
}
642+
Some(Node::Item(hir::Item {
643+
kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
644+
span: item_span,
645+
..
646+
})) => {
647+
tcx.sess.delay_span_bug(
648+
*item_span,
649+
"auto trait is invoked with no method error, but no error reported?",
650+
);
651+
}
652+
Some(_) => unreachable!(),
653+
None => (),
654+
}
655+
}
656+
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
657+
spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
658+
for (span, (_path, _self_ty, preds)) in spanned_predicates {
659+
let mut preds: Vec<_> = preds
660+
.into_iter()
661+
.filter_map(|pred| format_pred(*pred))
662+
.map(|(p, _)| format!("`{}`", p))
663+
.collect();
664+
preds.sort();
665+
preds.dedup();
666+
let msg = if let [pred] = &preds[..] {
667+
format!("trait bound {} was not satisfied", pred)
668+
} else {
669+
format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
670+
};
671+
err.span_note(span, &msg);
672+
unsatisfied_bounds = true;
673+
}
674+
675+
// The requirements that didn't have an `impl` span to show.
676+
let mut bound_list = unsatisfied_predicates
677+
.iter()
678+
.filter_map(|(pred, parent_pred, _cause)| {
679+
format_pred(*pred).map(|(p, self_ty)| {
680+
collect_type_param_suggestions(self_ty, *pred, &p);
681+
(
682+
match parent_pred {
683+
None => format!("`{}`", &p),
684+
Some(parent_pred) => match format_pred(*parent_pred) {
685+
None => format!("`{}`", &p),
686+
Some((parent_p, _)) => {
687+
collect_type_param_suggestions(self_ty, *parent_pred, &p);
688+
format!("`{}`\nwhich is required by `{}`", p, parent_p)
689+
}
690+
},
691+
},
692+
*pred,
693+
)
694+
})
695+
})
696+
.filter(|(_, pred)| !skip_list.contains(&pred))
697+
.map(|(t, _)| t)
698+
.enumerate()
699+
.collect::<Vec<(usize, String)>>();
700+
701+
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
702+
restrict_type_params = true;
703+
// #74886: Sort here so that the output is always the same.
704+
let mut obligations = obligations.into_iter().collect::<Vec<_>>();
705+
obligations.sort();
706+
err.span_suggestion_verbose(
707+
span,
708+
&format!(
709+
"consider restricting the type parameter{s} to satisfy the \
710+
trait bound{s}",
711+
s = pluralize!(obligations.len())
712+
),
713+
format!("{} {}", add_where_or_comma, obligations.join(", ")),
714+
Applicability::MaybeIncorrect,
715+
);
716+
}
717+
718+
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
719+
bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
720+
bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
721+
722+
if !bound_list.is_empty() || !skip_list.is_empty() {
723+
let bound_list =
724+
bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
725+
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
726+
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
727+
let (primary_message, label) = if unimplemented_traits.len() == 1
728+
&& unimplemented_traits_only
729+
{
730+
unimplemented_traits
731+
.into_iter()
732+
.next()
733+
.map(|(_, (trait_ref, obligation))| {
734+
if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
735+
{
736+
// Avoid crashing.
737+
return (None, None);
738+
}
739+
let OnUnimplementedNote { message, label, .. } =
740+
self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
741+
(message, label)
742+
})
743+
.unwrap()
744+
} else {
745+
(None, None)
746+
};
747+
let primary_message = primary_message.unwrap_or_else(|| {
748+
format!(
749+
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
750+
but its trait bounds were not satisfied"
751+
)
752+
});
753+
err.set_primary_message(&primary_message);
754+
if let Some(label) = label {
755+
custom_span_label = true;
756+
err.span_label(span, label);
757+
}
758+
if !bound_list.is_empty() {
759+
err.note(&format!(
760+
"the following trait bounds were not satisfied:\n{bound_list}"
761+
));
762+
}
763+
self.suggest_derive(&mut err, &unsatisfied_predicates);
764+
765+
unsatisfied_bounds = true;
766+
}
767+
}
768+
769+
let label_span_not_found = |err: &mut Diagnostic| {
770+
if unsatisfied_predicates.is_empty() {
771+
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
772+
let is_string_or_ref_str = match rcvr_ty.kind() {
773+
ty::Ref(_, ty, _) => {
774+
ty.is_str()
775+
|| matches!(
776+
ty.kind(),
777+
ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
778+
)
779+
}
780+
ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
781+
_ => false,
782+
};
783+
if is_string_or_ref_str && item_name.name == sym::iter {
784+
err.span_suggestion_verbose(
785+
item_name.span,
786+
"because of the in-memory representation of `&str`, to obtain \
787+
an `Iterator` over each of its codepoint use method `chars`",
788+
"chars",
789+
Applicability::MachineApplicable,
790+
);
791+
}
792+
if let ty::Adt(adt, _) = rcvr_ty.kind() {
793+
let mut inherent_impls_candidate = self
794+
.tcx
795+
.inherent_impls(adt.did())
796+
.iter()
797+
.copied()
798+
.filter(|def_id| {
799+
if let Some(assoc) = self.associated_value(*def_id, item_name) {
800+
// Check for both mode is the same so we avoid suggesting
801+
// incorrect associated item.
802+
match (mode, assoc.fn_has_self_parameter, source) {
803+
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
804+
// We check that the suggest type is actually
805+
// different from the received one
806+
// So we avoid suggestion method with Box<Self>
807+
// for instance
808+
self.tcx.at(span).type_of(*def_id) != rcvr_ty
809+
&& self.tcx.at(span).type_of(*def_id) != rcvr_ty
810+
}
811+
(Mode::Path, false, _) => true,
812+
_ => false,
813+
}
814+
} else {
815+
false
816+
}
817+
})
818+
.collect::<Vec<_>>();
819+
if !inherent_impls_candidate.is_empty() {
820+
inherent_impls_candidate.sort();
821+
inherent_impls_candidate.dedup();
822+
823+
// number of type to shows at most.
824+
let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
825+
let type_candidates = inherent_impls_candidate
826+
.iter()
827+
.take(limit)
828+
.map(|impl_item| {
829+
format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
830+
})
831+
.collect::<Vec<_>>()
832+
.join("\n");
833+
let additional_types = if inherent_impls_candidate.len() > limit {
834+
format!("\nand {} more types", inherent_impls_candidate.len() - limit)
835+
} else {
836+
"".to_string()
837+
};
838+
err.note(&format!(
839+
"the {item_kind} was found for\n{}{}",
840+
type_candidates, additional_types
841+
));
842+
}
843+
}
844+
} else {
845+
let ty_str =
846+
if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
847+
err.span_label(
848+
span,
849+
format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
850+
);
851+
}
852+
};
853+
854+
// If the method name is the name of a field with a function or closure type,
855+
// give a helping note that it has to be called as `(x.f)(...)`.
856+
if let SelfSource::MethodCall(expr) = source {
857+
if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
858+
&& lev_candidate.is_none()
859+
&& !custom_span_label
860+
{
861+
label_span_not_found(&mut err);
862+
}
863+
} else if !custom_span_label {
864+
label_span_not_found(&mut err);
865+
}
866+
867+
// Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
868+
// can't be called due to `typeof(expr): Clone` not holding.
869+
if unsatisfied_predicates.is_empty() {
870+
self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
871+
}
872+
873+
self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
874+
875+
bound_spans.sort();
876+
bound_spans.dedup();
877+
for (span, msg) in bound_spans.into_iter() {
878+
err.span_label(span, &msg);
879+
}
880+
881+
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
882+
} else {
883+
self.suggest_traits_to_import(
884+
&mut err,
885+
span,
886+
rcvr_ty,
887+
item_name,
888+
args.map(|(_, args)| args.len() + 1),
889+
source,
890+
no_match_data.out_of_scope_traits.clone(),
891+
&unsatisfied_predicates,
892+
&static_candidates,
893+
unsatisfied_bounds,
894+
);
895+
}
896+
897+
// Don't emit a suggestion if we found an actual method
898+
// that had unsatisfied trait bounds
899+
if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
900+
let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
901+
if let Some(suggestion) = lev_distance::find_best_match_for_name(
902+
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
903+
item_name.name,
904+
None,
905+
) {
906+
err.span_suggestion(
907+
span,
908+
"there is a variant with a similar name",
909+
suggestion,
910+
Applicability::MaybeIncorrect,
911+
);
912+
}
913+
}
914+
915+
if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
916+
let msg = "remove this method call";
917+
let mut fallback_span = true;
918+
if let SelfSource::MethodCall(expr) = source {
919+
let call_expr =
920+
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
921+
if let Some(span) = call_expr.span.trim_start(expr.span) {
922+
err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
923+
fallback_span = false;
924+
}
925+
}
926+
if fallback_span {
927+
err.span_label(span, msg);
928+
}
929+
} else if let Some(lev_candidate) = lev_candidate {
930+
// Don't emit a suggestion if we found an actual method
931+
// that had unsatisfied trait bounds
932+
if unsatisfied_predicates.is_empty() {
933+
let def_kind = lev_candidate.kind.as_def_kind();
934+
// Methods are defined within the context of a struct and their first parameter is always self,
935+
// which represents the instance of the struct the method is being called on
936+
// Associated functions don’t take self as a parameter and
937+
// they are not methods because they don’t have an instance of the struct to work with.
938+
if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
939+
err.span_suggestion(
940+
span,
941+
"there is a method with a similar name",
942+
lev_candidate.name,
943+
Applicability::MaybeIncorrect,
944+
);
945+
} else {
946+
err.span_suggestion(
947+
span,
948+
&format!(
949+
"there is {} {} with a similar name",
950+
def_kind.article(),
951+
def_kind.descr(lev_candidate.def_id),
952+
),
953+
lev_candidate.name,
954+
Applicability::MaybeIncorrect,
955+
);
956+
}
957+
}
958+
}
959+
960+
self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
961+
return Some(err);
962+
}
963+
964+
fn note_candidates_on_method_error(
965+
&self,
966+
rcvr_ty: Ty<'tcx>,
967+
item_name: Ident,
968+
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
969+
span: Span,
970+
err: &mut Diagnostic,
971+
sources: &mut Vec<CandidateSource>,
972+
sugg_span: Option<Span>,
973+
) {
974+
sources.sort();
975+
sources.dedup();
976+
// Dynamic limit to avoid hiding just one candidate, which is silly.
977+
let limit = if sources.len() == 5 { 5 } else { 4 };
978+
979+
for (idx, source) in sources.iter().take(limit).enumerate() {
980+
match *source {
981+
CandidateSource::Impl(impl_did) => {
982+
// Provide the best span we can. Use the item, if local to crate, else
983+
// the impl, if local to crate (item may be defaulted), else nothing.
984+
let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
985+
let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
986+
self.associated_value(impl_trait_ref.def_id, item_name)
987+
}) else {
988+
continue;
989+
};
990+
991+
let note_span = if item.def_id.is_local() {
992+
Some(self.tcx.def_span(item.def_id))
993+
} else if impl_did.is_local() {
994+
Some(self.tcx.def_span(impl_did))
995+
} else {
996+
None
997+
};
998+
999+
let impl_ty = self.tcx.at(span).type_of(impl_did);
1000+
1001+
let insertion = match self.tcx.impl_trait_ref(impl_did) {
1002+
None => String::new(),
1003+
Some(trait_ref) => {
1004+
format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
1005+
}
1006+
};
1007+
1008+
let (note_str, idx) = if sources.len() > 1 {
1009+
(
1010+
format!(
1011+
"candidate #{} is defined in an impl{} for the type `{}`",
1012+
idx + 1,
1013+
insertion,
1014+
impl_ty,
1015+
),
1016+
Some(idx + 1),
1017+
)
1018+
} else {
1019+
(
1020+
format!(
1021+
"the candidate is defined in an impl{} for the type `{}`",
1022+
insertion, impl_ty,
1023+
),
1024+
None,
1025+
)
1026+
};
1027+
if let Some(note_span) = note_span {
1028+
// We have a span pointing to the method. Show note with snippet.
1029+
err.span_note(note_span, &note_str);
1030+
} else {
1031+
err.note(&note_str);
1032+
}
1033+
if let Some(sugg_span) = sugg_span
1034+
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
1035+
let path = self.tcx.def_path_str(trait_ref.def_id);
1036+
1037+
let ty = match item.kind {
1038+
ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
1039+
ty::AssocKind::Fn => self
1040+
.tcx
1041+
.fn_sig(item.def_id)
1042+
.inputs()
1043+
.skip_binder()
1044+
.get(0)
1045+
.filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
1046+
.copied()
1047+
.unwrap_or(rcvr_ty),
1048+
};
1049+
print_disambiguation_help(
1050+
item_name,
1051+
args,
1052+
err,
1053+
path,
1054+
ty,
1055+
item.kind,
1056+
item.def_id,
1057+
sugg_span,
1058+
idx,
1059+
self.tcx.sess.source_map(),
1060+
item.fn_has_self_parameter,
1061+
);
1062+
}
1063+
}
1064+
CandidateSource::Trait(trait_did) => {
1065+
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
1066+
let item_span = self.tcx.def_span(item.def_id);
1067+
let idx = if sources.len() > 1 {
1068+
let msg = &format!(
1069+
"candidate #{} is defined in the trait `{}`",
1070+
idx + 1,
1071+
self.tcx.def_path_str(trait_did)
1072+
);
1073+
err.span_note(item_span, msg);
1074+
Some(idx + 1)
1075+
} else {
1076+
let msg = &format!(
1077+
"the candidate is defined in the trait `{}`",
1078+
self.tcx.def_path_str(trait_did)
1079+
);
1080+
err.span_note(item_span, msg);
1081+
None
1082+
};
1083+
if let Some(sugg_span) = sugg_span {
1084+
let path = self.tcx.def_path_str(trait_did);
1085+
print_disambiguation_help(
1086+
item_name,
1087+
args,
1088+
err,
1089+
path,
1090+
rcvr_ty,
1091+
item.kind,
1092+
item.def_id,
1093+
sugg_span,
1094+
idx,
1095+
self.tcx.sess.source_map(),
1096+
item.fn_has_self_parameter,
1097+
);
1098+
}
1099+
}
1100+
}
1101+
}
1102+
if sources.len() > limit {
1103+
err.note(&format!("and {} others", sources.len() - limit));
1104+
}
1105+
}
1106+
11021107
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
11031108
/// doesn't take a `self` receiver.
11041109
fn suggest_associated_call_syntax(

0 commit comments

Comments
 (0)
Please sign in to comment.