1use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2use rustc_data_structures::sorted_map::SortedMap;
3use rustc_data_structures::unord::UnordMap;
4use rustc_errors::codes::*;
5use rustc_errors::{
6 Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, msg, pluralize,
7 struct_span_code_err,
8};
9use rustc_hir::def::{CtorOf, DefKind, Res};
10use rustc_hir::def_id::DefId;
11use rustc_hir::{self as hir, HirId};
12use rustc_middle::bug;
13use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
14use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
15use rustc_middle::ty::{
16 self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
17 suggest_constraining_type_param,
18};
19use rustc_session::errors::feature_err;
20use rustc_span::edit_distance::find_best_match_for_name;
21use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
22use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
23use rustc_trait_selection::traits::{
24 FulfillmentError, dyn_compatibility_violations_for_assoc_item,
25};
26use smallvec::SmallVec;
27use tracing::debug;
28
29use super::InherentAssocCandidate;
30use crate::diagnostics::{
31 self, AssocItemConstraintsNotAllowedHere, ManualImplementation, ParenthesizedFnTraitExpansion,
32 TraitObjectDeclaredWithNoTraits,
33};
34use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
35
36impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
37 pub(crate) fn report_missing_generic_params(
38 &self,
39 missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
40 def_id: DefId,
41 span: Span,
42 empty_generic_args: bool,
43 ) {
44 if missing_generic_params.is_empty() {
45 return;
46 }
47
48 self.dcx().emit_err(diagnostics::MissingGenericParams {
49 span,
50 def_span: self.tcx().def_span(def_id),
51 span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
52 missing_generic_params,
53 empty_generic_args,
54 });
55 }
56
57 pub(crate) fn report_internal_fn_trait(
60 &self,
61 span: Span,
62 trait_def_id: DefId,
63 trait_segment: &'_ hir::PathSegment<'_>,
64 is_impl: bool,
65 ) {
66 if self.tcx().features().unboxed_closures() {
67 return;
68 }
69
70 let trait_def = self.tcx().trait_def(trait_def_id);
71 if !trait_def.paren_sugar {
72 if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar {
73 feature_err(
75 &self.tcx().sess,
76 sym::unboxed_closures,
77 span,
78 "parenthetical notation is only stable when used with `Fn`-family traits",
79 )
80 .emit();
81 }
82
83 return;
84 }
85
86 let sess = self.tcx().sess;
87
88 if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar {
89 let mut err = feature_err(
91 sess,
92 sym::unboxed_closures,
93 span,
94 "the precise format of `Fn`-family traits' type parameters is subject to change",
95 );
96 if !is_impl {
99 err.span_suggestion(
100 span,
101 "use parenthetical notation instead",
102 fn_trait_to_string(self.tcx(), trait_segment, true),
103 Applicability::MaybeIncorrect,
104 );
105 }
106 err.emit();
107 }
108
109 if is_impl {
110 let trait_name = self.tcx().def_path_str(trait_def_id);
111 self.dcx().emit_err(ManualImplementation { span, trait_name });
112 }
113 }
114
115 pub(super) fn report_unresolved_assoc_item<I>(
116 &self,
117 all_candidates: impl Fn() -> I,
118 qself: AssocItemQSelf,
119 assoc_tag: ty::AssocTag,
120 assoc_ident: Ident,
121 span: Span,
122 constraint: Option<&hir::AssocItemConstraint<'tcx>>,
123 ) -> ErrorGuaranteed
124 where
125 I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
126 {
127 let tcx = self.tcx();
128
129 if let Some(assoc_item) = all_candidates().find_map(|r| {
131 tcx.associated_items(r.def_id())
132 .filter_by_name_unhygienic(assoc_ident.name)
133 .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id()))
134 }) {
135 return self.report_assoc_kind_mismatch(
136 assoc_item,
137 assoc_tag,
138 assoc_ident,
139 span,
140 constraint,
141 );
142 }
143
144 let assoc_kind = assoc_tag_str(assoc_tag);
145 let qself_str = qself.to_string(tcx);
146
147 let is_dummy = assoc_ident.span == DUMMY_SP;
150
151 let mut err = diagnostics::AssocItemNotFound {
152 span: if is_dummy { span } else { assoc_ident.span },
153 assoc_ident,
154 assoc_kind,
155 qself: &qself_str,
156 label: None,
157 sugg: None,
158 within_macro_span: assoc_ident.span.within_macro(span, tcx.sess.source_map()),
161 };
162
163 if is_dummy {
164 err.label = Some(diagnostics::AssocItemNotFoundLabel::NotFound {
165 span,
166 assoc_ident,
167 assoc_kind,
168 });
169 return self.dcx().emit_err(err);
170 }
171
172 let all_candidate_names: Vec<_> = all_candidates()
173 .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
174 .filter_map(|item| {
175 if !item.is_impl_trait_in_trait() && item.tag() == assoc_tag {
176 item.opt_name()
177 } else {
178 None
179 }
180 })
181 .collect();
182
183 if let Some(suggested_name) =
184 find_best_match_for_name(&all_candidate_names, assoc_ident.name, None)
185 {
186 err.sugg = Some(diagnostics::AssocItemNotFoundSugg::Similar {
187 span: assoc_ident.span,
188 assoc_kind,
189 suggested_name,
190 });
191 return self.dcx().emit_err(err);
192 }
193
194 let visible_traits: Vec<_> = tcx
199 .visible_traits()
200 .filter(|trait_def_id| {
201 let viz = tcx.visibility(*trait_def_id);
202 let def_id = self.item_def_id();
203 viz.is_accessible_from(def_id, tcx)
204 })
205 .collect();
206
207 let wider_candidate_names: Vec<_> = visible_traits
208 .iter()
209 .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
210 .filter_map(|item| {
211 (!item.is_impl_trait_in_trait() && item.tag() == assoc_tag).then(|| item.name())
212 })
213 .collect();
214
215 if let Some(suggested_name) =
216 find_best_match_for_name(&wider_candidate_names, assoc_ident.name, None)
217 {
218 if let [best_trait] = visible_traits
219 .iter()
220 .copied()
221 .filter(|&trait_def_id| {
222 tcx.associated_items(trait_def_id)
223 .filter_by_name_unhygienic(suggested_name)
224 .any(|item| item.tag() == assoc_tag)
225 })
226 .collect::<Vec<_>>()[..]
227 {
228 let trait_name = tcx.def_path_str(best_trait);
229 err.label = Some(diagnostics::AssocItemNotFoundLabel::FoundInOtherTrait {
230 span: assoc_ident.span,
231 assoc_kind,
232 trait_name: &trait_name,
233 suggested_name,
234 identically_named: suggested_name == assoc_ident.name,
235 });
236 if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself
237 && let item_def_id =
241 tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
242 && let Some(generics) = tcx.hir_get_generics(item_def_id.def_id)
244 {
245 if generics
249 .bounds_for_param(ty_param_def_id)
250 .flat_map(|pred| pred.bounds.iter())
251 .any(|b| match b {
252 hir::GenericBound::Trait(t, ..) => {
253 t.trait_ref.trait_def_id() == Some(best_trait)
254 }
255 _ => false,
256 })
257 {
258 err.sugg = Some(diagnostics::AssocItemNotFoundSugg::SimilarInOtherTrait {
261 span: assoc_ident.span,
262 trait_name: &trait_name,
263 assoc_kind,
264 suggested_name,
265 });
266 return self.dcx().emit_err(err);
267 }
268
269 let trait_args = &ty::GenericArgs::identity_for_item(tcx, best_trait)[1..];
270 let mut trait_ref = trait_name.clone();
271 let applicability = if let [arg, args @ ..] = trait_args {
272 use std::fmt::Write;
273 trait_ref.write_fmt(format_args!("</* {0}", arg))write!(trait_ref, "</* {arg}").unwrap();
274 args.iter().try_for_each(|arg| trait_ref.write_fmt(format_args!(", {0}", arg))write!(trait_ref, ", {arg}")).unwrap();
275 trait_ref += " */>";
276 Applicability::HasPlaceholders
277 } else {
278 Applicability::MaybeIncorrect
279 };
280
281 let identically_named = suggested_name == assoc_ident.name;
282
283 if let DefKind::TyAlias = tcx.def_kind(item_def_id)
284 && !tcx.type_alias_is_lazy(item_def_id)
285 {
286 err.sugg =
287 Some(diagnostics::AssocItemNotFoundSugg::SimilarInOtherTraitQPath {
288 lo: ty_param_span.shrink_to_lo(),
289 mi: ty_param_span.shrink_to_hi(),
290 hi: (!identically_named).then_some(assoc_ident.span),
291 trait_ref,
292 identically_named,
293 suggested_name,
294 assoc_kind,
295 applicability,
296 });
297 } else {
298 let mut err = self.dcx().create_err(err);
299 if suggest_constraining_type_param(
300 tcx,
301 generics,
302 &mut err,
303 &qself_str,
304 &trait_ref,
305 Some(best_trait),
306 None,
307 ) && !identically_named
308 {
309 err.span_suggestion_verbose(
312 assoc_ident.span,
313 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("...and changing the associated {$assoc_kind} name"))msg!("...and changing the associated {$assoc_kind} name"),
314 suggested_name,
315 Applicability::MaybeIncorrect,
316 );
317 }
318 return err.emit();
319 }
320 }
321 return self.dcx().emit_err(err);
322 }
323 }
324
325 if let [candidate_name] = all_candidate_names.as_slice() {
328 err.sugg = Some(diagnostics::AssocItemNotFoundSugg::Other {
329 span: assoc_ident.span,
330 qself: &qself_str,
331 assoc_kind,
332 suggested_name: *candidate_name,
333 });
334 } else {
335 err.label = Some(diagnostics::AssocItemNotFoundLabel::NotFound {
336 span: assoc_ident.span,
337 assoc_ident,
338 assoc_kind,
339 });
340 }
341
342 self.dcx().emit_err(err)
343 }
344
345 fn report_assoc_kind_mismatch(
346 &self,
347 assoc_item: &ty::AssocItem,
348 assoc_tag: ty::AssocTag,
349 ident: Ident,
350 span: Span,
351 constraint: Option<&hir::AssocItemConstraint<'tcx>>,
352 ) -> ErrorGuaranteed {
353 let tcx = self.tcx();
354
355 let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
356 && let Some(constraint) = constraint
357 && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
358 {
359 let lo = if constraint.gen_args.span_ext.is_dummy() {
360 ident.span
361 } else {
362 constraint.gen_args.span_ext
363 };
364 Some(lo.between(span.shrink_to_hi()))
365 } else {
366 None
367 };
368
369 let wrap_in_braces_sugg = if let Some(constraint) = constraint
371 && let Some(hir_ty) = constraint.ty()
372 && let ty = self.lower_ty(hir_ty)
373 && (ty.is_enum() || ty.references_error())
374 && tcx.features().min_generic_const_args()
375 {
376 Some(diagnostics::AssocKindMismatchWrapInBracesSugg {
377 lo: hir_ty.span.shrink_to_lo(),
378 hi: hir_ty.span.shrink_to_hi(),
379 })
380 } else {
381 None
382 };
383
384 let (span, expected_because_label, expected, got) = if let Some(constraint) = constraint
387 && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
388 {
389 let span = match term {
390 hir::Term::Ty(ty) => ty.span,
391 hir::Term::Const(ct) => ct.span,
392 };
393 (span, Some(ident.span), assoc_item.tag(), assoc_tag)
394 } else {
395 (ident.span, None, assoc_tag, assoc_item.tag())
396 };
397
398 self.dcx().emit_err(diagnostics::AssocKindMismatch {
399 span,
400 expected: assoc_tag_str(expected),
401 got: assoc_tag_str(got),
402 expected_because_label,
403 assoc_kind: assoc_tag_str(assoc_item.tag()),
404 def_span: tcx.def_span(assoc_item.def_id),
405 bound_on_assoc_const_label,
406 wrap_in_braces_sugg,
407 })
408 }
409
410 pub(super) fn report_ambiguous_assoc_item(
411 &self,
412 matching_candidates: &[ty::PolyTraitRef<'tcx>],
413 qself: AssocItemQSelf,
414 assoc_tag: ty::AssocTag,
415 assoc_ident: Ident,
416 span: Span,
417 constraint: Option<&hir::AssocItemConstraint<'tcx>>,
418 ) -> ErrorGuaranteed {
419 let tcx = self.tcx();
420
421 let assoc_kind_str = assoc_tag_str(assoc_tag);
422 let qself_str = qself.to_string(tcx);
423 let mut err = self.dcx().create_err(crate::diagnostics::AmbiguousAssocItem {
424 span,
425 assoc_kind: assoc_kind_str,
426 assoc_ident,
427 qself: &qself_str,
428 });
429 err.code(
431 if let Some(constraint) = constraint
432 && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind
433 {
434 E0222
435 } else {
436 E0221
437 },
438 );
439
440 let mut where_bounds = ::alloc::vec::Vec::new()vec![];
444 for &bound in matching_candidates {
445 let bound_id = bound.def_id();
446 let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
447 tcx,
448 assoc_ident,
449 assoc_tag,
450 bound_id,
451 );
452 let bound_span = assoc_item.and_then(|item| tcx.hir_span_if_local(item.def_id));
453
454 if let Some(bound_span) = bound_span {
455 err.span_label(
456 bound_span,
457 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("ambiguous `{1}` from `{0}`",
bound.print_trait_sugared(), assoc_ident))
})format!("ambiguous `{assoc_ident}` from `{}`", bound.print_trait_sugared(),),
458 );
459 if let Some(constraint) = constraint {
460 match constraint.kind {
461 hir::AssocItemConstraintKind::Equality { term } => {
462 let term: ty::Term<'_> = match term {
463 hir::Term::Ty(ty) => self.lower_ty(ty).into(),
464 hir::Term::Const(ct) => {
465 let assoc_item =
466 assoc_item.expect("assoc_item should be present");
467 let projection_term = bound.map_bound(|trait_ref| {
468 let item_segment = hir::PathSegment {
469 ident: constraint.ident,
470 hir_id: constraint.hir_id,
471 res: Res::Err,
472 args: Some(constraint.gen_args),
473 infer_args: false,
474 delegation_child_segment: false,
475 };
476
477 let alias_args = self.lower_generic_args_of_assoc_item(
478 constraint.ident.span,
479 assoc_item.def_id,
480 &item_segment,
481 trait_ref.args,
482 );
483 ty::AliasTerm::new_from_def_id(
484 tcx,
485 assoc_item.def_id,
486 alias_args,
487 )
488 });
489
490 let ty = projection_term.map_bound(|alias| {
493 alias.expect_ct().type_of(tcx).skip_norm_wip()
494 });
495 let ty = super::bounds::check_assoc_const_binding_type(
496 self,
497 constraint.ident,
498 ty,
499 constraint.hir_id,
500 );
501
502 self.lower_const_arg(ct, ty).into()
503 }
504 };
505 if term.references_error() {
506 continue;
507 }
508 where_bounds.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" T: {0}::{1} = {2}",
bound.print_only_trait_path(), assoc_ident, term))
})format!(
510 " T: {trait}::{assoc_ident} = {term}",
511 trait = bound.print_only_trait_path(),
512 ));
513 }
514 hir::AssocItemConstraintKind::Bound { bounds: _ } => {}
516 }
517 } else {
518 err.span_suggestion_verbose(
519 span.with_hi(assoc_ident.span.lo()),
520 "use fully-qualified syntax to disambiguate",
521 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{1} as {0}>::",
bound.print_only_trait_path(), qself_str))
})format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
522 Applicability::MaybeIncorrect,
523 );
524 }
525 } else {
526 let trait_ = tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
527 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("associated {0} `{1}` could derive from `{2}`",
assoc_kind_str, assoc_ident, trait_))
})format!(
528 "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
529 ));
530 }
531 }
532 if !where_bounds.is_empty() {
533 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider introducing a new type parameter `T` and adding `where` constraints:\n where\n T: {1},\n{0}",
where_bounds.join(",\n"), qself_str))
})format!(
534 "consider introducing a new type parameter `T` and adding `where` constraints:\
535 \n where\n T: {qself_str},\n{}",
536 where_bounds.join(",\n"),
537 ));
538 }
539 err.emit()
540 }
541
542 pub(crate) fn report_missing_self_ty_for_resolved_path(
543 &self,
544 trait_def_id: DefId,
545 span: Span,
546 item_segment: &hir::PathSegment<'tcx>,
547 assoc_tag: ty::AssocTag,
548 ) -> ErrorGuaranteed {
549 let tcx = self.tcx();
550 let path_str = tcx.def_path_str(trait_def_id);
551
552 let def_id = self.item_def_id();
553 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs:553",
"rustc_hir_analysis::hir_ty_lowering::errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs"),
::tracing_core::__macro_support::Option::Some(553u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::hir_ty_lowering::errors"),
::tracing_core::field::FieldSet::new(&["item_def_id"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&def_id) as
&dyn Value))])
});
} else { ; }
};debug!(item_def_id = ?def_id);
554
555 let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
557 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs:557",
"rustc_hir_analysis::hir_ty_lowering::errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs"),
::tracing_core::__macro_support::Option::Some(557u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::hir_ty_lowering::errors"),
::tracing_core::field::FieldSet::new(&["parent_def_id"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&parent_def_id)
as &dyn Value))])
});
} else { ; }
};debug!(?parent_def_id);
558
559 let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
562 let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
563
564 let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
565 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
["Self".to_string()]))vec!["Self".to_string()]
566 } else {
567 tcx.all_impls(trait_def_id)
569 .map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
570 .filter(|header| {
571 tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
573 && header.polarity != ty::ImplPolarity::Negative
574 })
575 .map(|header| header.trait_ref.instantiate_identity().skip_norm_wip().self_ty())
576 .filter(|self_ty| !self_ty.has_non_region_param())
578 .map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string())
579 .collect()
580 };
581 self.report_ambiguous_assoc_item_path(
585 span,
586 &type_names,
587 &[path_str],
588 item_segment.ident,
589 assoc_tag,
590 )
591 }
592
593 pub(super) fn report_unresolved_type_relative_path(
594 &self,
595 self_ty: Ty<'tcx>,
596 hir_self_ty: &hir::Ty<'_>,
597 assoc_tag: ty::AssocTag,
598 ident: Ident,
599 qpath_hir_id: HirId,
600 span: Span,
601 variant_def_id: Option<DefId>,
602 ) -> ErrorGuaranteed {
603 let tcx = self.tcx();
604 let kind_str = assoc_tag_str(assoc_tag);
605 if variant_def_id.is_some() {
606 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}, found variant `{1}`",
kind_str, ident))
})format!("expected {kind_str}, found variant `{ident}`");
608 self.dcx().span_err(span, msg)
609 } else if self_ty.is_enum() {
610 let mut err = self.dcx().create_err(diagnostics::NoVariantNamed {
611 span: ident.span,
612 ident,
613 ty: self_ty,
614 });
615
616 let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
617 if let Some(variant_name) = find_best_match_for_name(
618 &adt_def.variants().iter().map(|variant| variant.name).collect::<Vec<Symbol>>(),
619 ident.name,
620 None,
621 ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name)
622 {
623 let mut suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ident.span, variant_name.to_string())]))vec![(ident.span, variant_name.to_string())];
624 if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. })
625 | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
626 && let hir::ExprKind::Struct(..) = expr.kind
627 {
628 match variant.ctor {
629 None => {
630 suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ident.span.with_hi(expr.span.hi()),
if variant.fields.is_empty() {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {{}}", variant_name))
})
} else {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1} {{ {0} }}",
variant.fields.iter().map(|f|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: /* value */",
f.name))
})).collect::<Vec<_>>().join(", "), variant_name))
})
})]))vec![(
632 ident.span.with_hi(expr.span.hi()),
633 if variant.fields.is_empty() {
634 format!("{variant_name} {{}}")
635 } else {
636 format!(
637 "{variant_name} {{ {} }}",
638 variant
639 .fields
640 .iter()
641 .map(|f| format!("{}: /* value */", f.name))
642 .collect::<Vec<_>>()
643 .join(", ")
644 )
645 },
646 )];
647 }
648 Some((hir::def::CtorKind::Fn, def_id)) => {
649 let fn_sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
651 let inputs = fn_sig.inputs().skip_binder();
652 suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ident.span.with_hi(expr.span.hi()),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}({0})",
inputs.iter().map(|i|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("/* {0} */", i))
})).collect::<Vec<_>>().join(", "), variant_name))
}))]))vec![(
653 ident.span.with_hi(expr.span.hi()),
654 format!(
655 "{variant_name}({})",
656 inputs
657 .iter()
658 .map(|i| format!("/* {i} */"))
659 .collect::<Vec<_>>()
660 .join(", ")
661 ),
662 )];
663 }
664 Some((hir::def::CtorKind::Const, _)) => {
665 suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ident.span.with_hi(expr.span.hi()), variant_name.to_string())]))vec![(
667 ident.span.with_hi(expr.span.hi()),
668 variant_name.to_string(),
669 )];
670 }
671 }
672 }
673 err.multipart_suggestion(
674 "there is a variant with a similar name",
675 suggestion,
676 Applicability::HasPlaceholders,
677 );
678 } else {
679 err.span_label(ident.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("variant not found in `{0}`",
self_ty))
})format!("variant not found in `{self_ty}`"));
680 }
681
682 if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
683 err.span_label(sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("variant `{0}` not found here",
ident))
})format!("variant `{ident}` not found here"));
684 }
685
686 err.emit()
687 } else if let Err(reported) = self_ty.error_reported() {
688 reported
689 } else {
690 match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) {
691 Ok(()) => {}
692 Err(reported) => return reported,
693 }
694
695 let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
696
697 self.report_ambiguous_assoc_item_path(
698 span,
699 &[self_ty.to_string()],
700 &traits,
701 ident,
702 assoc_tag,
703 )
704 }
705 }
706
707 fn report_ambiguous_assoc_item_path(
708 &self,
709 span: Span,
710 types: &[String],
711 traits: &[String],
712 ident: Ident,
713 assoc_tag: ty::AssocTag,
714 ) -> ErrorGuaranteed {
715 let kind_str = assoc_tag_str(assoc_tag);
716 let mut err =
717 {
self.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("ambiguous associated {0}",
kind_str))
})).with_code(E0223)
}struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
718 if self
719 .tcx()
720 .resolutions(())
721 .confused_type_with_std_module
722 .keys()
723 .any(|full_span| full_span.contains(span))
724 {
725 err.span_suggestion_verbose(
726 span.shrink_to_lo(),
727 "you are looking for the module in `std`, not the primitive type",
728 "std::",
729 Applicability::MachineApplicable,
730 );
731 } else {
732 let sugg_sp = span.until(ident.span);
733
734 let mut types = types.to_vec();
735 types.sort();
736 let mut traits = traits.to_vec();
737 traits.sort();
738 match (&types[..], &traits[..]) {
739 ([], []) => {
740 err.span_suggestion_verbose(
741 sugg_sp,
742 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if there were a type named `Type` that implements a trait named `Trait` with associated {0} `{1}`, you could use the fully-qualified path",
kind_str, ident))
})format!(
743 "if there were a type named `Type` that implements a trait named \
744 `Trait` with associated {kind_str} `{ident}`, you could use the \
745 fully-qualified path",
746 ),
747 "<Type as Trait>::",
748 Applicability::HasPlaceholders,
749 );
750 }
751 ([], [trait_str]) => {
752 err.span_suggestion_verbose(
753 sugg_sp,
754 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if there were a type named `Example` that implemented `{0}`, you could use the fully-qualified path",
trait_str))
})format!(
755 "if there were a type named `Example` that implemented `{trait_str}`, \
756 you could use the fully-qualified path",
757 ),
758 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<Example as {0}>::", trait_str))
})format!("<Example as {trait_str}>::"),
759 Applicability::HasPlaceholders,
760 );
761 }
762 ([], traits) => {
763 err.span_suggestions_with_style(
764 sugg_sp,
765 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if there were a type named `Example` that implemented one of the traits with associated {0} `{1}`, you could use the fully-qualified path",
kind_str, ident))
})format!(
766 "if there were a type named `Example` that implemented one of the \
767 traits with associated {kind_str} `{ident}`, you could use the \
768 fully-qualified path",
769 ),
770 traits.iter().map(|trait_str| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<Example as {0}>::", trait_str))
})format!("<Example as {trait_str}>::")),
771 Applicability::HasPlaceholders,
772 SuggestionStyle::ShowAlways,
773 );
774 }
775 ([type_str], []) => {
776 err.span_suggestion_verbose(
777 sugg_sp,
778 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if there were a trait named `Example` with associated {0} `{1}` implemented for `{2}`, you could use the fully-qualified path",
kind_str, ident, type_str))
})format!(
779 "if there were a trait named `Example` with associated {kind_str} `{ident}` \
780 implemented for `{type_str}`, you could use the fully-qualified path",
781 ),
782 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0} as Example>::", type_str))
})format!("<{type_str} as Example>::"),
783 Applicability::HasPlaceholders,
784 );
785 }
786 (types, []) => {
787 err.span_suggestions_with_style(
788 sugg_sp,
789 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("if there were a trait named `Example` with associated {0} `{1}` implemented for one of the types, you could use the fully-qualified path",
kind_str, ident))
})format!(
790 "if there were a trait named `Example` with associated {kind_str} `{ident}` \
791 implemented for one of the types, you could use the fully-qualified \
792 path",
793 ),
794 types
795 .into_iter()
796 .map(|type_str| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0} as Example>::", type_str))
})format!("<{type_str} as Example>::")),
797 Applicability::HasPlaceholders,
798 SuggestionStyle::ShowAlways,
799 );
800 }
801 (types, traits) => {
802 let mut suggestions = ::alloc::vec::Vec::new()vec![];
803 for type_str in types {
804 for trait_str in traits {
805 suggestions.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0} as {1}>::", type_str,
trait_str))
})format!("<{type_str} as {trait_str}>::"));
806 }
807 }
808 err.span_suggestions_with_style(
809 sugg_sp,
810 "use fully-qualified syntax",
811 suggestions,
812 Applicability::MachineApplicable,
813 SuggestionStyle::ShowAlways,
814 );
815 }
816 }
817 }
818 err.emit()
819 }
820
821 pub(crate) fn report_ambiguous_inherent_assoc_item(
822 &self,
823 name: Ident,
824 candidates: Vec<DefId>,
825 span: Span,
826 ) -> ErrorGuaranteed {
827 let mut err = {
self.dcx().struct_span_err(name.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple applicable items in scope"))
})).with_code(E0034)
}struct_span_code_err!(
828 self.dcx(),
829 name.span,
830 E0034,
831 "multiple applicable items in scope"
832 );
833 err.span_label(name.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("multiple `{0}` found", name))
})format!("multiple `{name}` found"));
834 self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span);
835 err.emit()
836 }
837
838 fn note_ambiguous_inherent_assoc_item(
840 &self,
841 err: &mut Diag<'_>,
842 candidates: Vec<DefId>,
843 span: Span,
844 ) {
845 let tcx = self.tcx();
846
847 let limit = if candidates.len() == 5 { 5 } else { 4 };
849
850 for (index, &item) in candidates.iter().take(limit).enumerate() {
851 let impl_ = tcx.parent(item);
852
853 let note_span = if item.is_local() {
854 Some(tcx.def_span(item))
855 } else if impl_.is_local() {
856 Some(tcx.def_span(impl_))
857 } else {
858 None
859 };
860
861 let title = if candidates.len() > 1 {
862 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("candidate #{0}", index + 1))
})format!("candidate #{}", index + 1)
863 } else {
864 "the candidate".into()
865 };
866
867 let impl_ty = tcx.at(span).type_of(impl_).instantiate_identity().skip_norm_wip();
868 let note = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} is defined in an impl for the type `{1}`",
title, impl_ty))
})format!("{title} is defined in an impl for the type `{impl_ty}`");
869
870 if let Some(span) = note_span {
871 err.span_note(span, note);
872 } else {
873 err.note(note);
874 }
875 }
876 if candidates.len() > limit {
877 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("and {0} others",
candidates.len() - limit))
})format!("and {} others", candidates.len() - limit));
878 }
879 }
880
881 pub(crate) fn report_unresolved_inherent_assoc_item(
883 &self,
884 name: Ident,
885 self_ty: Ty<'tcx>,
886 candidates: Vec<InherentAssocCandidate>,
887 fulfillment_errors: Vec<FulfillmentError<'tcx>>,
888 span: Span,
889 assoc_tag: ty::AssocTag,
890 ) -> ErrorGuaranteed {
891 let tcx = self.tcx();
898
899 let assoc_tag_str = assoc_tag_str(assoc_tag);
900 let adt_did = self_ty.ty_adt_def().map(|def| def.did());
901 let add_def_label = |err: &mut Diag<'_>| {
902 if let Some(did) = adt_did {
903 err.span_label(
904 tcx.def_span(did),
905 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("associated {1} `{2}` not found for this {0}",
tcx.def_descr(did), assoc_tag_str, name))
})format!(
906 "associated {assoc_tag_str} `{name}` not found for this {}",
907 tcx.def_descr(did)
908 ),
909 );
910 }
911 };
912
913 if fulfillment_errors.is_empty() {
914 let limit = if candidates.len() == 5 { 5 } else { 4 };
917 let type_candidates = candidates
918 .iter()
919 .take(limit)
920 .map(|cand| {
921 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("- `{0}`",
tcx.at(span).type_of(cand.impl_).instantiate_identity().skip_norm_wip()))
})format!(
922 "- `{}`",
923 tcx.at(span).type_of(cand.impl_).instantiate_identity().skip_norm_wip()
924 )
925 })
926 .collect::<Vec<_>>()
927 .join("\n");
928 let additional_types = if candidates.len() > limit {
929 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\nand {0} more types",
candidates.len() - limit))
})format!("\nand {} more types", candidates.len() - limit)
930 } else {
931 String::new()
932 };
933
934 let mut err = {
self.dcx().struct_span_err(name.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("associated {0} `{1}` not found for `{2}` in the current scope",
assoc_tag_str, name, self_ty))
})).with_code(E0220)
}struct_span_code_err!(
935 self.dcx(),
936 name.span,
937 E0220,
938 "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
939 );
940 err.span_label(name.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("associated item not found in `{0}`",
self_ty))
})format!("associated item not found in `{self_ty}`"));
941 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the associated {0} was found for\n{1}{2}",
assoc_tag_str, type_candidates, additional_types))
})format!(
942 "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
943 ));
944 add_def_label(&mut err);
945 return err.emit();
946 }
947
948 let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
949
950 let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
951 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`",
if obligation.len() > 50 { quiet } else { obligation }))
})format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
952 match self_ty.kind() {
953 ty::Adt(def, _) => {
955 bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
956 }
957 ty::Dynamic(preds, _) => {
959 for pred in preds.iter() {
960 match pred.skip_binder() {
961 ty::ExistentialPredicate::Trait(tr) => {
962 bound_spans
963 .get_mut_or_insert_default(tcx.def_span(tr.def_id))
964 .push(msg.clone());
965 }
966 ty::ExistentialPredicate::Projection(_)
967 | ty::ExistentialPredicate::AutoTrait(_) => {}
968 }
969 }
970 }
971 ty::Closure(def_id, _) => {
973 bound_spans
974 .get_mut_or_insert_default(tcx.def_span(*def_id))
975 .push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", quiet))
})format!("`{quiet}`"));
976 }
977 _ => {}
978 }
979 };
980
981 let format_pred = |pred: ty::Predicate<'tcx>| {
982 let bound_predicate = pred.kind();
983 match bound_predicate.skip_binder() {
984 ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
985 let projection_term = pred.projection_term;
987 let term = pred.term;
988 let self_ty = projection_term.args.get(0).and_then(|arg| arg.as_type())?;
989
990 let obligation = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} = {1}", projection_term, term))
})format!("{projection_term} = {term}");
991 let quiet_projection_term = projection_term
992 .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
993 let quiet = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} = {1}", quiet_projection_term,
term))
})format!("{quiet_projection_term} = {term}");
994
995 bound_span_label(self_ty, &obligation, &quiet);
996
997 Some(obligation)
998 }
999 ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
1000 let p = poly_trait_ref.trait_ref;
1001 let self_ty = p.self_ty();
1002 let path = p.print_only_trait_path();
1003 let obligation = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: {1}", self_ty, path))
})format!("{self_ty}: {path}");
1004 let quiet = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("_: {0}", path))
})format!("_: {path}");
1005 bound_span_label(self_ty, &obligation, &quiet);
1006 Some(obligation)
1007 }
1008 _ => None,
1009 }
1010 };
1011
1012 let mut bounds: Vec<_> = fulfillment_errors
1015 .into_iter()
1016 .map(|error| error.root_obligation.predicate)
1017 .filter_map(format_pred)
1018 .map(|p| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", p))
})format!("`{p}`"))
1019 .collect();
1020 bounds.sort();
1021 bounds.dedup();
1022
1023 let mut err = self.dcx().struct_span_err(
1024 name.span,
1025 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the associated {0} `{1}` exists for `{2}`, but its trait bounds were not satisfied",
assoc_tag_str, name, self_ty))
})format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
1026 );
1027 if !bounds.is_empty() {
1028 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the following trait bounds were not satisfied:\n{0}",
bounds.join("\n")))
})format!(
1029 "the following trait bounds were not satisfied:\n{}",
1030 bounds.join("\n")
1031 ));
1032 }
1033 err.span_label(
1034 name.span,
1035 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("associated {0} cannot be referenced on `{1}` due to unsatisfied trait bounds",
assoc_tag_str, self_ty))
})format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
1036 );
1037
1038 for (span, mut bounds) in bound_spans {
1039 if !tcx.sess.source_map().is_span_accessible(span) {
1040 continue;
1041 }
1042 bounds.sort();
1043 bounds.dedup();
1044 let msg = match &bounds[..] {
1045 [bound] => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("doesn\'t satisfy {0}", bound))
})format!("doesn't satisfy {bound}"),
1046 bounds if bounds.len() > 4 => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("doesn\'t satisfy {0} bounds",
bounds.len()))
})format!("doesn't satisfy {} bounds", bounds.len()),
1047 [bounds @ .., last] => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("doesn\'t satisfy {0} or {1}",
bounds.join(", "), last))
})format!("doesn't satisfy {} or {last}", bounds.join(", ")),
1048 [] => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1049 };
1050 err.span_label(span, msg);
1051 }
1052 add_def_label(&mut err);
1053 err.emit()
1054 }
1055
1056 pub(crate) fn check_for_required_assoc_items(
1060 &self,
1061 spans: SmallVec<[Span; 1]>,
1062 missing_assoc_items: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
1063 potential_assoc_items: Vec<usize>,
1064 trait_bounds: &[hir::PolyTraitRef<'_>],
1065 ) -> Result<(), ErrorGuaranteed> {
1066 if missing_assoc_items.is_empty() {
1067 return Ok(());
1068 }
1069
1070 let tcx = self.tcx();
1071 let principal_span = *spans.first().unwrap();
1072
1073 let missing_assoc_items: Vec<_> = missing_assoc_items
1075 .into_iter()
1076 .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
1077 .collect();
1078 let mut names: FxIndexMap<_, Vec<_>> = Default::default();
1079 let mut names_len = 0;
1080 let mut descr = None;
1081
1082 enum Descr {
1083 Item,
1084 Tag(ty::AssocTag),
1085 }
1086
1087 for &(assoc_item, trait_ref) in &missing_assoc_items {
1088 let violations =
1096 dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), assoc_item);
1097 if !violations.is_empty() {
1098 return Err(report_dyn_incompatibility(
1099 tcx,
1100 principal_span,
1101 None,
1102 trait_ref.def_id(),
1103 &violations,
1104 )
1105 .emit());
1106 }
1107
1108 names.entry(trait_ref).or_default().push(assoc_item.name());
1109 names_len += 1;
1110
1111 descr = match descr {
1112 None => Some(Descr::Tag(assoc_item.tag())),
1113 Some(Descr::Tag(tag)) if tag != assoc_item.tag() => Some(Descr::Item),
1114 _ => continue,
1115 };
1116 }
1117
1118 let mut in_expr_or_pat = false;
1120 if let ([], [bound]) = (&potential_assoc_items[..], &trait_bounds) {
1121 let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
1122 in_expr_or_pat = match grandparent {
1123 hir::Node::Expr(_) | hir::Node::Pat(_) => true,
1124 _ => false,
1125 };
1126 }
1127
1128 let bound_names: UnordMap<_, _> =
1137 trait_bounds
1138 .iter()
1139 .filter_map(|poly_trait_ref| {
1140 let path = poly_trait_ref.trait_ref.path.segments.last()?;
1141 let args = path.args?;
1142 let Res::Def(DefKind::Trait, trait_def_id) = path.res else { return None };
1143
1144 Some(args.constraints.iter().filter_map(move |constraint| {
1145 let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
1146 else {
1147 return None;
1148 };
1149 let tag = match term {
1150 hir::Term::Ty(_) => ty::AssocTag::Type,
1151 hir::Term::Const(_) => ty::AssocTag::Const,
1152 };
1153 let assoc_item = tcx
1154 .associated_items(trait_def_id)
1155 .find_by_ident_and_kind(tcx, constraint.ident, tag, trait_def_id)?;
1156 Some(((constraint.ident.name, tag), assoc_item.def_id))
1157 }))
1158 })
1159 .flatten()
1160 .collect();
1161
1162 let mut names: Vec<_> = names
1163 .into_iter()
1164 .map(|(trait_, mut assocs)| {
1165 assocs.sort();
1166 let trait_ = trait_.print_trait_sugared();
1167 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} in `{1}`",
listify(&assocs[..],
|a|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", a))
})).unwrap_or_default(), trait_))
})format!(
1168 "{} in `{trait_}`",
1169 listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
1170 )
1171 })
1172 .collect();
1173 names.sort();
1174 let names = names.join(", ");
1175
1176 let descr = match descr.unwrap() {
1177 Descr::Item => "associated item",
1178 Descr::Tag(tag) => tag.descr(),
1179 };
1180 let mut err = {
self.dcx().struct_span_err(principal_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the value of the {1}{0} {2} must be specified",
if names_len == 1 { "" } else { "s" }, descr, names))
})).with_code(E0191)
}struct_span_code_err!(
1181 self.dcx(),
1182 principal_span,
1183 E0191,
1184 "the value of the {descr}{s} {names} must be specified",
1185 s = pluralize!(names_len),
1186 );
1187 let mut suggestions = ::alloc::vec::Vec::new()vec![];
1188 let mut items_count = 0;
1189 let mut where_constraints = ::alloc::vec::Vec::new()vec![];
1190 let mut already_has_generics_args_suggestion = false;
1191
1192 let mut names: UnordMap<_, usize> = Default::default();
1193 for (item, _) in &missing_assoc_items {
1194 items_count += 1;
1195 *names.entry((item.name(), item.tag())).or_insert(0) += 1;
1196 }
1197 let mut dupes = false;
1198 let mut shadows = false;
1199 for (item, trait_ref) in &missing_assoc_items {
1200 let name = item.name();
1201 let key = (name, item.tag());
1202
1203 if names[&key] > 1 {
1204 dupes = true;
1205 } else if bound_names.get(&key).is_some_and(|&def_id| def_id != item.def_id) {
1206 shadows = true;
1207 }
1208
1209 let prefix = if dupes || shadows {
1210 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::",
tcx.def_path_str(trait_ref.def_id())))
})format!("{}::", tcx.def_path_str(trait_ref.def_id()))
1211 } else {
1212 String::new()
1213 };
1214 let mut is_shadowed = false;
1215
1216 if let Some(&def_id) = bound_names.get(&key)
1217 && def_id != item.def_id
1218 {
1219 is_shadowed = true;
1220
1221 let rename_message = if def_id.is_local() { ", consider renaming it" } else { "" };
1222 err.span_label(
1223 tcx.def_span(def_id),
1224 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}{1}` shadowed here{2}", prefix,
name, rename_message))
})format!("`{prefix}{name}` shadowed here{rename_message}"),
1225 );
1226 }
1227
1228 let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
1229
1230 if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
1231 err.span_label(sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}{1}` defined here{2}", prefix,
name, rename_message))
})format!("`{prefix}{name}` defined here{rename_message}"));
1232 }
1233 }
1234 if potential_assoc_items.len() == missing_assoc_items.len() {
1235 already_has_generics_args_suggestion = true;
1239 } else if let (Ok(snippet), false, false) =
1240 (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
1241 {
1242 let bindings: Vec<_> = missing_assoc_items
1243 .iter()
1244 .map(|(item, _)| {
1245 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} = /* {1} */", item.name(),
match item.kind {
ty::AssocKind::Const { .. } => "CONST",
ty::AssocKind::Type { .. } => "Type",
ty::AssocKind::Fn { .. } =>
::core::panicking::panic("internal error: entered unreachable code"),
}))
})format!(
1246 "{} = /* {} */",
1247 item.name(),
1248 match item.kind {
1249 ty::AssocKind::Const { .. } => "CONST",
1250 ty::AssocKind::Type { .. } => "Type",
1251 ty::AssocKind::Fn { .. } => unreachable!(),
1252 }
1253 )
1254 })
1255 .collect();
1256 let code = if let Some(snippet) = snippet.strip_suffix("<>") {
1257 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}<{0}>", bindings.join(", "),
snippet))
})format!("{snippet}<{}>", bindings.join(", "))
1259 } else if let Some(snippet) = snippet.strip_suffix('>') {
1260 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}, {0}>", bindings.join(", "),
snippet))
})format!("{snippet}, {}>", bindings.join(", "))
1262 } else if in_expr_or_pat {
1263 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::<{1}>", snippet,
bindings.join(", ")))
})format!("{}::<{}>", snippet, bindings.join(", "))
1266 } else {
1267 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}<{1}>", snippet,
bindings.join(", ")))
})format!("{}<{}>", snippet, bindings.join(", "))
1270 };
1271 suggestions.push((principal_span, code));
1272 } else if dupes {
1273 where_constraints.push(principal_span);
1274 }
1275
1276 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
1285 using the fully-qualified path to the associated types";
1286 if !where_constraints.is_empty() && suggestions.is_empty() {
1287 err.help(where_msg);
1291 }
1292 if suggestions.len() != 1 || already_has_generics_args_suggestion {
1293 let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
1295 for (item, _) in &missing_assoc_items {
1296 items_count += 1;
1297 *names.entry(item.name()).or_insert(0) += 1;
1298 }
1299 let mut label = ::alloc::vec::Vec::new()vec![];
1300 for (item, trait_ref) in &missing_assoc_items {
1301 let name = item.name();
1302 let postfix = if names[&name] > 1 {
1303 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" (from trait `{0}`)",
trait_ref.print_trait_sugared()))
})format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
1304 } else {
1305 String::new()
1306 };
1307 label.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`{1}", name, postfix))
})format!("`{}`{}", name, postfix));
1308 }
1309 if !label.is_empty() {
1310 err.span_label(
1311 principal_span,
1312 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{2}{0} {1} must be specified",
if label.len() == 1 { "" } else { "s" }, label.join(", "),
descr))
})format!(
1313 "{descr}{s} {names} must be specified",
1314 s = pluralize!(label.len()),
1315 names = label.join(", "),
1316 ),
1317 );
1318 }
1319 }
1320 suggestions.sort_by_key(|&(span, _)| span);
1321 let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
1334 if !suggestions.is_empty() && !overlaps {
1335 err.multipart_suggestion(
1336 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("specify the {1}{0}",
if items_count == 1 { "" } else { "s" }, descr))
})format!("specify the {descr}{s}", s = pluralize!(items_count)),
1337 suggestions,
1338 Applicability::HasPlaceholders,
1339 );
1340 if !where_constraints.is_empty() {
1341 err.span_help(where_constraints, where_msg);
1342 }
1343 }
1344
1345 Err(err.emit())
1346 }
1347
1348 pub(crate) fn maybe_report_similar_assoc_fn(
1352 &self,
1353 span: Span,
1354 qself_ty: Ty<'tcx>,
1355 qself: &hir::Ty<'_>,
1356 ) -> Result<(), ErrorGuaranteed> {
1357 let tcx = self.tcx();
1358 if let Some((_, node)) = tcx.hir_parent_iter(qself.hir_id).skip(1).next()
1359 && let hir::Node::Expr(hir::Expr {
1360 kind:
1361 hir::ExprKind::Path(hir::QPath::TypeRelative(
1362 hir::Ty {
1363 kind:
1364 hir::TyKind::Path(hir::QPath::TypeRelative(
1365 _,
1366 hir::PathSegment { ident: ident2, .. },
1367 )),
1368 ..
1369 },
1370 hir::PathSegment { ident: ident3, .. },
1371 )),
1372 ..
1373 }) = node
1374 && let Some(inherent_impls) = qself_ty
1375 .ty_adt_def()
1376 .map(|adt_def| tcx.inherent_impls(adt_def.did()))
1377 .or_else(|| {
1378 simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer)
1379 .map(|simple_ty| tcx.incoherent_impls(simple_ty))
1380 })
1381 && let name = Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_{1}", ident2, ident3))
})format!("{ident2}_{ident3}"))
1382 && let Some(item) = inherent_impls
1383 .iter()
1384 .flat_map(|&inherent_impl| {
1385 tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
1386 })
1387 .next()
1388 && item.is_fn()
1389 {
1390 Err({
self.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("ambiguous associated type"))
})).with_code(E0223)
}struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
1391 .with_span_suggestion_verbose(
1392 ident2.span.to(ident3.span),
1393 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("there is an associated function with a similar name: `{0}`",
name))
})format!("there is an associated function with a similar name: `{name}`"),
1394 name,
1395 Applicability::MaybeIncorrect,
1396 )
1397 .emit())
1398 } else {
1399 Ok(())
1400 }
1401 }
1402
1403 pub fn report_prohibited_generic_args<'a>(
1404 &self,
1405 segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1406 args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
1407 err_extend: GenericsArgsErrExtend<'a>,
1408 ) -> ErrorGuaranteed {
1409 #[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for ProhibitGenericsArg {
#[inline]
fn eq(&self, other: &ProhibitGenericsArg) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ProhibitGenericsArg {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for ProhibitGenericsArg {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash)]
1410 enum ProhibitGenericsArg {
1411 Lifetime,
1412 Type,
1413 Const,
1414 Infer,
1415 }
1416
1417 let mut prohibit_args = FxIndexSet::default();
1418 args_visitors.for_each(|arg| {
1419 match arg {
1420 hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
1421 hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
1422 hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
1423 hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
1424 };
1425 });
1426
1427 let segments: Vec<_> = segments.collect();
1428 let types_and_spans: Vec<_> = segments
1429 .iter()
1430 .flat_map(|segment| {
1431 if segment.args().args.is_empty() {
1432 None
1433 } else {
1434 Some((
1435 match segment.res {
1436 Res::PrimTy(ty) => {
1437 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} `{1}`", segment.res.descr(),
ty.name()))
})format!("{} `{}`", segment.res.descr(), ty.name())
1438 }
1439 Res::Def(_, def_id)
1440 if let Some(name) = self.tcx().opt_item_name(def_id) =>
1441 {
1442 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} `{1}`", segment.res.descr(),
name))
})format!("{} `{name}`", segment.res.descr())
1443 }
1444 Res::Err => "this type".to_string(),
1445 _ => segment.res.descr().to_string(),
1446 },
1447 segment.ident.span,
1448 ))
1449 }
1450 })
1451 .collect();
1452 let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
1453 .expect("expected one segment to deny");
1454
1455 let arg_spans: Vec<Span> =
1456 segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect();
1457
1458 let mut kinds = Vec::with_capacity(4);
1459 prohibit_args.iter().for_each(|arg| match arg {
1460 ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
1461 ProhibitGenericsArg::Type => kinds.push("type"),
1462 ProhibitGenericsArg::Const => kinds.push("const"),
1463 ProhibitGenericsArg::Infer => kinds.push("generic"),
1464 });
1465
1466 let s = if kinds.len() == 1 { "" } else { "s" }pluralize!(kinds.len());
1467 let kind =
1468 listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
1469 let last_span = *arg_spans.last().unwrap();
1470 let span: MultiSpan = arg_spans.into();
1471 let mut err = {
self.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} arguments are not allowed on {1}",
kind, this_type))
})).with_code(E0109)
}struct_span_code_err!(
1472 self.dcx(),
1473 span,
1474 E0109,
1475 "{kind} arguments are not allowed on {this_type}",
1476 );
1477 err.span_label(last_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} argument{1} not allowed", kind,
s))
})format!("{kind} argument{s} not allowed"));
1478 for (what, span) in types_and_spans {
1479 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("not allowed on {0}", what))
})format!("not allowed on {what}"));
1480 }
1481 generics_args_err_extend(self.tcx(), segments.into_iter(), &mut err, err_extend);
1482 err.emit()
1483 }
1484
1485 pub fn report_trait_object_addition_traits(
1486 &self,
1487 regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
1488 ) -> ErrorGuaranteed {
1489 let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap();
1492 let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap();
1493 let mut err = {
self.dcx().struct_span_err(*regular_traits[1].1.first().unwrap(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("only auto traits can be used as additional traits in a trait object"))
})).with_code(E0225)
}struct_span_code_err!(
1494 self.dcx(),
1495 *regular_traits[1].1.first().unwrap(),
1496 E0225,
1497 "only auto traits can be used as additional traits in a trait object"
1498 );
1499 err.span_label(first_span, "first non-auto trait");
1500 for &alias_span in first_alias_spans {
1501 err.span_label(alias_span, "first non-auto trait comes from this alias");
1502 }
1503 err.span_label(second_span, "additional non-auto trait");
1504 for &alias_span in second_alias_spans {
1505 err.span_label(alias_span, "second non-auto trait comes from this alias");
1506 }
1507 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: {0} {{}}`",
regular_traits.iter().map(|(pred, _)|
pred.map_bound(|pred|
pred.trait_ref).print_only_trait_path().to_string()).collect::<Vec<_>>().join(" + ")))
})format!(
1508 "consider creating a new trait with all of these as supertraits and using that \
1509 trait here instead: `trait NewTrait: {} {{}}`",
1510 regular_traits
1511 .iter()
1512 .map(|(pred, _)| pred
1514 .map_bound(|pred| pred.trait_ref)
1515 .print_only_trait_path()
1516 .to_string())
1517 .collect::<Vec<_>>()
1518 .join(" + "),
1519 ));
1520 err.note(
1521 "auto-traits like `Send` and `Sync` are traits that have special properties; \
1522 for more information on them, visit \
1523 <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
1524 );
1525 err.emit()
1526 }
1527
1528 pub fn report_trait_object_with_no_traits(
1529 &self,
1530 span: Span,
1531 user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
1532 ) -> ErrorGuaranteed {
1533 let tcx = self.tcx();
1534 let trait_alias_span = user_written_clauses
1535 .into_iter()
1536 .filter_map(|(clause, _)| clause.as_trait_clause())
1537 .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id()))
1538 .map(|trait_ref| tcx.def_span(trait_ref.def_id()));
1539
1540 self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
1541 }
1542}
1543
1544pub fn prohibit_assoc_item_constraint(
1546 cx: &dyn HirTyLowerer<'_>,
1547 constraint: &hir::AssocItemConstraint<'_>,
1548 segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
1549) -> ErrorGuaranteed {
1550 let tcx = cx.tcx();
1551 let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
1552 span: constraint.span,
1553 fn_trait_expansion: if let Some((_, segment, span)) = segment
1554 && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
1555 {
1556 Some(ParenthesizedFnTraitExpansion {
1557 span,
1558 expanded_type: fn_trait_to_string(tcx, segment, false),
1559 })
1560 } else {
1561 None
1562 },
1563 });
1564
1565 if let Some((def_id, segment, _)) = segment
1569 && segment.args().parenthesized == hir::GenericArgsParentheses::No
1570 {
1571 let suggest_removal = |e: &mut Diag<'_>| {
1573 let constraints = segment.args().constraints;
1574 let args = segment.args().args;
1575
1576 let Some(index) = constraints.iter().position(|b| b.hir_id == constraint.hir_id) else {
1588 ::rustc_middle::util::bug::bug_fmt(format_args!("a type binding exists but its HIR ID not found in generics"));bug!("a type binding exists but its HIR ID not found in generics");
1589 };
1590
1591 let preceding_span = if index > 0 {
1592 Some(constraints[index - 1].span)
1593 } else {
1594 args.last().map(|a| a.span())
1595 };
1596
1597 let next_span = constraints.get(index + 1).map(|constraint| constraint.span);
1598
1599 let removal_span = match (preceding_span, next_span) {
1600 (Some(prec), _) => constraint.span.with_lo(prec.hi()),
1601 (None, Some(next)) => constraint.span.with_hi(next.lo()),
1602 (None, None) => {
1603 let Some(generics_span) = segment.args().span_ext() else {
1604 ::rustc_middle::util::bug::bug_fmt(format_args!("a type binding exists but generic span is empty"));bug!("a type binding exists but generic span is empty");
1605 };
1606
1607 generics_span
1608 }
1609 };
1610
1611 e.span_suggestion_verbose(
1613 removal_span,
1614 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider removing this associated item {0}",
constraint.kind.descr()))
})format!("consider removing this associated item {}", constraint.kind.descr()),
1615 "",
1616 Applicability::MaybeIncorrect,
1617 );
1618 };
1619
1620 let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
1623 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
1624 e.span_suggestion_verbose(
1625 constraint.span,
1626 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("to use `{0}` as a generic argument specify it directly",
snippet))
})format!("to use `{snippet}` as a generic argument specify it directly"),
1627 snippet,
1628 Applicability::MaybeIncorrect,
1629 );
1630 }
1631 };
1632
1633 let generics = tcx.generics_of(def_id);
1636 let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name);
1637
1638 if let Some(matching_param) = matching_param {
1640 match (constraint.kind, &matching_param.kind) {
1641 (
1642 hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) },
1643 GenericParamDefKind::Type { .. },
1644 ) => suggest_direct_use(&mut err, ty.span),
1645 (
1646 hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
1647 GenericParamDefKind::Const { .. },
1648 ) => {
1649 suggest_direct_use(&mut err, c.span);
1650 }
1651 (hir::AssocItemConstraintKind::Bound { bounds }, _) => {
1652 let impl_block = tcx
1658 .hir_parent_iter(constraint.hir_id)
1659 .find_map(|(_, node)| node.impl_block_of_trait(def_id));
1660
1661 let type_with_constraints =
1662 tcx.sess.source_map().span_to_snippet(constraint.span);
1663
1664 if let Some(impl_block) = impl_block
1665 && let Ok(type_with_constraints) = type_with_constraints
1666 {
1667 let lifetimes: String = bounds
1670 .iter()
1671 .filter_map(|bound| {
1672 if let hir::GenericBound::Outlives(lifetime) = bound {
1673 Some(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}, ", lifetime))
})format!("{lifetime}, "))
1674 } else {
1675 None
1676 }
1677 })
1678 .collect();
1679 let param_decl = if let Some(param_span) =
1682 impl_block.generics.span_for_param_suggestion()
1683 {
1684 (param_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", {0}{1}", lifetimes,
type_with_constraints))
})format!(", {lifetimes}{type_with_constraints}"))
1685 } else {
1686 (
1687 impl_block.generics.span.shrink_to_lo(),
1688 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}{1}>", lifetimes,
type_with_constraints))
})format!("<{lifetimes}{type_with_constraints}>"),
1689 )
1690 };
1691 let suggestions = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[param_decl,
(constraint.span.with_lo(constraint.ident.span.hi()),
String::new())]))vec![
1692 param_decl,
1693 (constraint.span.with_lo(constraint.ident.span.hi()), String::new()),
1694 ];
1695
1696 err.multipart_suggestion(
1697 "declare the type parameter right after the `impl` keyword",
1698 suggestions,
1699 Applicability::MaybeIncorrect,
1700 );
1701 }
1702 }
1703 _ => suggest_removal(&mut err),
1704 }
1705 } else {
1706 suggest_removal(&mut err);
1707 }
1708 }
1709
1710 err.emit()
1711}
1712
1713pub(crate) fn fn_trait_to_string(
1714 tcx: TyCtxt<'_>,
1715 trait_segment: &hir::PathSegment<'_>,
1716 parenthesized: bool,
1717) -> String {
1718 let args = trait_segment
1719 .args
1720 .and_then(|args| args.args.first())
1721 .and_then(|arg| match arg {
1722 hir::GenericArg::Type(ty) => match ty.kind {
1723 hir::TyKind::Tup(t) => t
1724 .iter()
1725 .map(|e| tcx.sess.source_map().span_to_snippet(e.span))
1726 .collect::<Result<Vec<_>, _>>()
1727 .map(|a| a.join(", ")),
1728 _ => tcx.sess.source_map().span_to_snippet(ty.span),
1729 }
1730 .map(|s| {
1731 if parenthesized || s.is_empty() { ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("({0})", s))
})format!("({s})") } else { ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("({0},)", s))
})format!("({s},)") }
1733 })
1734 .ok(),
1735 _ => None,
1736 })
1737 .unwrap_or_else(|| "()".to_string());
1738
1739 let ret = trait_segment
1740 .args()
1741 .constraints
1742 .iter()
1743 .find_map(|c| {
1744 if c.ident.name == sym::Output
1745 && let Some(ty) = c.ty()
1746 && ty.span != tcx.hir_span(trait_segment.hir_id)
1747 {
1748 tcx.sess.source_map().span_to_snippet(ty.span).ok()
1749 } else {
1750 None
1751 }
1752 })
1753 .unwrap_or_else(|| "()".to_string());
1754
1755 if parenthesized {
1756 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1} -> {2}",
trait_segment.ident, args, ret))
})format!("{}{} -> {}", trait_segment.ident, args, ret)
1757 } else {
1758 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}<{1}, Output={2}>",
trait_segment.ident, args, ret))
})format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
1759 }
1760}
1761
1762pub enum GenericsArgsErrExtend<'tcx> {
1764 EnumVariant {
1765 qself: &'tcx hir::Ty<'tcx>,
1766 assoc_segment: &'tcx hir::PathSegment<'tcx>,
1767 adt_def: AdtDef<'tcx>,
1768 },
1769 OpaqueTy,
1770 PrimTy(hir::PrimTy),
1771 SelfTyAlias {
1772 def_id: DefId,
1773 span: Span,
1774 },
1775 SelfTyParam(Span),
1776 Param(DefId),
1777 DefVariant(&'tcx [hir::PathSegment<'tcx>]),
1778 None,
1779}
1780
1781fn generics_args_err_extend<'a>(
1782 tcx: TyCtxt<'_>,
1783 segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1784 err: &mut Diag<'_>,
1785 err_extend: GenericsArgsErrExtend<'a>,
1786) {
1787 match err_extend {
1788 GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
1789 err.note("enum variants can't have type parameters");
1790 let type_name = tcx.item_name(adt_def.did());
1791 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you might have meant to specify type parameters on enum `{0}`",
type_name))
})format!(
1792 "you might have meant to specify type parameters on enum \
1793 `{type_name}`"
1794 );
1795 let Some(args) = assoc_segment.args else {
1796 return;
1797 };
1798 let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
1803 if tcx.generics_of(adt_def.did()).is_empty() {
1804 err.span_suggestion_verbose(
1807 args_span,
1808 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} doesn\'t have generic parameters",
type_name))
})format!("{type_name} doesn't have generic parameters"),
1809 "",
1810 Applicability::MachineApplicable,
1811 );
1812 return;
1813 }
1814 let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
1815 err.note(msg);
1816 return;
1817 };
1818 let (qself_sugg_span, is_self) =
1819 if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1820 match &path.segments {
1823 [
1827 ..,
1828 hir::PathSegment {
1829 ident, args, res: Res::Def(DefKind::Enum, _), ..
1830 },
1831 _,
1832 ] => (
1833 ident
1836 .span
1837 .shrink_to_hi()
1838 .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
1839 false,
1840 ),
1841 [segment] => {
1842 (
1843 segment.ident.span.shrink_to_hi().to(segment
1846 .args
1847 .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
1848 kw::SelfUpper == segment.ident.name,
1849 )
1850 }
1851 _ => {
1852 err.note(msg);
1853 return;
1854 }
1855 }
1856 } else {
1857 err.note(msg);
1858 return;
1859 };
1860 let suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[if is_self {
(qself.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", type_name,
snippet))
}))
} else { (qself_sugg_span, snippet) },
(args_span, String::new())]))vec![
1861 if is_self {
1862 (qself.span, format!("{type_name}{snippet}"))
1866 } else {
1867 (qself_sugg_span, snippet)
1868 },
1869 (args_span, String::new()),
1870 ];
1871 err.multipart_suggestion(msg, suggestion, Applicability::MaybeIncorrect);
1872 }
1873 GenericsArgsErrExtend::DefVariant(segments) => {
1874 let args: Vec<Span> = segments
1875 .iter()
1876 .filter_map(|segment| match segment.res {
1877 Res::Def(
1878 DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant | DefKind::Enum,
1879 _,
1880 ) => segment.args().span_ext().map(|s| s.with_lo(segment.ident.span.hi())),
1881 _ => None,
1882 })
1883 .collect();
1884 if args.len() > 1
1885 && let Some(span) = args.into_iter().next_back()
1886 {
1887 err.note(
1888 "generic arguments are not allowed on both an enum and its variant's path \
1889 segments simultaneously; they are only valid in one place or the other",
1890 );
1891 err.span_suggestion_verbose(
1892 span,
1893 "remove the generics arguments from one of the path segments",
1894 String::new(),
1895 Applicability::MaybeIncorrect,
1896 );
1897 }
1898 }
1899 GenericsArgsErrExtend::PrimTy(prim_ty) => {
1900 let name = prim_ty.name_str();
1901 for segment in segments {
1902 if let Some(args) = segment.args {
1903 err.span_suggestion_verbose(
1904 segment.ident.span.shrink_to_hi().to(args.span_ext),
1905 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("primitive type `{0}` doesn\'t have generic parameters",
name))
})format!("primitive type `{name}` doesn't have generic parameters"),
1906 "",
1907 Applicability::MaybeIncorrect,
1908 );
1909 }
1910 }
1911 }
1912 GenericsArgsErrExtend::OpaqueTy => {
1913 err.note("`impl Trait` types can't have type parameters");
1914 }
1915 GenericsArgsErrExtend::Param(def_id) => {
1916 let span = tcx.def_ident_span(def_id).unwrap();
1917 let kind = tcx.def_descr(def_id);
1918 let name = tcx.item_name(def_id);
1919 err.span_note(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} `{1}` defined here", kind,
name))
})format!("{kind} `{name}` defined here"));
1920 }
1921 GenericsArgsErrExtend::SelfTyParam(span) => {
1922 err.span_suggestion_verbose(
1923 span,
1924 "the `Self` type doesn't accept type parameters",
1925 "",
1926 Applicability::MaybeIncorrect,
1927 );
1928 }
1929 GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
1930 let ty = tcx.at(span).type_of(def_id).instantiate_identity().skip_norm_wip();
1931 let span_of_impl = tcx.span_of_impl(def_id);
1932 let ty::Adt(self_def, _) = *ty.kind() else { return };
1933 let def_id = self_def.did();
1934
1935 let type_name = tcx.item_name(def_id);
1936 let span_of_ty = tcx.def_ident_span(def_id);
1937 let generics = tcx.generics_of(def_id).count();
1938
1939 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`Self` is of type `{0}`", ty))
})format!("`Self` is of type `{ty}`");
1940 if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
1941 let mut span: MultiSpan = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[t_sp]))vec![t_sp].into();
1942 span.push_span_label(
1943 i_sp,
1944 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`Self` is on type `{0}` in this `impl`",
type_name))
})format!("`Self` is on type `{type_name}` in this `impl`"),
1945 );
1946 let mut postfix = "";
1947 if generics == 0 {
1948 postfix = ", which doesn't have generic parameters";
1949 }
1950 span.push_span_label(t_sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`Self` corresponds to this type{0}",
postfix))
})format!("`Self` corresponds to this type{postfix}"));
1951 err.span_note(span, msg);
1952 } else {
1953 err.note(msg);
1954 }
1955 for segment in segments {
1956 if let Some(args) = segment.args
1957 && segment.ident.name == kw::SelfUpper
1958 {
1959 if generics == 0 {
1960 err.span_suggestion_verbose(
1963 segment.ident.span.shrink_to_hi().to(args.span_ext),
1964 "the `Self` type doesn't accept type parameters",
1965 "",
1966 Applicability::MachineApplicable,
1967 );
1968 return;
1969 } else {
1970 err.span_suggestion_verbose(
1971 segment.ident.span,
1972 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the `Self` type doesn\'t accept type parameters, use the concrete type\'s name `{0}` instead if you want to specify its type parameters",
type_name))
})format!(
1973 "the `Self` type doesn't accept type parameters, use the \
1974 concrete type's name `{type_name}` instead if you want to \
1975 specify its type parameters"
1976 ),
1977 type_name,
1978 Applicability::MaybeIncorrect,
1979 );
1980 }
1981 }
1982 }
1983 }
1984 _ => {}
1985 }
1986}
1987
1988pub(super) struct AmbiguityBetweenVariantAndAssocItem<'tcx> {
1989 pub(super) variant_def_id: DefId,
1990 pub(super) item_def_id: DefId,
1991 pub(super) span: Span,
1992 pub(super) segment_ident: Ident,
1993 pub(super) bound_def_id: DefId,
1994 pub(super) self_ty: Ty<'tcx>,
1995 pub(super) tcx: TyCtxt<'tcx>,
1996 pub(super) mode: super::LowerTypeRelativePathMode,
1997}
1998
1999impl<'a, 'tcx> rustc_errors::Diagnostic<'a, ()> for AmbiguityBetweenVariantAndAssocItem<'tcx> {
2000 fn into_diag(
2001 self,
2002 dcx: rustc_errors::DiagCtxtHandle<'a>,
2003 level: rustc_errors::Level,
2004 ) -> Diag<'a, ()> {
2005 let Self {
2006 variant_def_id,
2007 item_def_id,
2008 span,
2009 segment_ident,
2010 bound_def_id,
2011 self_ty,
2012 tcx,
2013 mode,
2014 } = self;
2015 let mut lint = Diag::new(dcx, level, "ambiguous associated item");
2016
2017 let mut could_refer_to = |kind: DefKind, def_id, also| {
2018 let note_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` could{1} refer to the {2} defined here",
segment_ident, also, tcx.def_kind_descr(kind, def_id)))
})format!(
2019 "`{}` could{} refer to the {} defined here",
2020 segment_ident,
2021 also,
2022 tcx.def_kind_descr(kind, def_id)
2023 );
2024 lint.span_note(tcx.def_span(def_id), note_msg);
2025 };
2026
2027 could_refer_to(DefKind::Variant, variant_def_id, "");
2028 could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also");
2029
2030 lint.span_suggestion(
2031 span,
2032 "use fully-qualified syntax",
2033 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0} as {1}>::{2}", self_ty,
tcx.item_name(bound_def_id), segment_ident))
})format!("<{} as {}>::{}", self_ty, tcx.item_name(bound_def_id), segment_ident),
2034 Applicability::MachineApplicable,
2035 );
2036 lint
2037 }
2038}
2039
2040fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
2041 match assoc_tag {
2042 ty::AssocTag::Fn => "function",
2043 ty::AssocTag::Const => "constant",
2044 ty::AssocTag::Type => "type",
2045 }
2046}