1use std::borrow::Cow;
4use std::iter;
5use std::ops::Deref;
6
7use rustc_ast::ptr::P;
8use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty};
9use rustc_ast::{
10 self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind,
11 Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind,
12};
13use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
14use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
15use rustc_errors::codes::*;
16use rustc_errors::{
17 Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,
18 struct_span_code_err,
19};
20use rustc_hir as hir;
21use rustc_hir::def::Namespace::{self, *};
22use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
23use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
24use rustc_hir::{MissingLifetimeKind, PrimTy};
25use rustc_middle::ty;
26use rustc_session::{Session, lint};
27use rustc_span::edit_distance::find_best_match_for_name;
28use rustc_span::edition::Edition;
29use rustc_span::hygiene::MacroKind;
30use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
31use thin_vec::ThinVec;
32use tracing::debug;
33
34use super::NoConstantGenericsReason;
35use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
36use crate::late::{
37 AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
38 LifetimeUseSet, RibKind,
39};
40use crate::ty::fast_reject::SimplifiedType;
41use crate::{
42 Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors,
43 path_names_to_string,
44};
45
46type Res = def::Res<ast::NodeId>;
47
48enum AssocSuggestion {
50 Field(Span),
51 MethodWithSelf { called: bool },
52 AssocFn { called: bool },
53 AssocType,
54 AssocConst,
55}
56
57impl AssocSuggestion {
58 fn action(&self) -> &'static str {
59 match self {
60 AssocSuggestion::Field(_) => "use the available field",
61 AssocSuggestion::MethodWithSelf { called: true } => {
62 "call the method with the fully-qualified path"
63 }
64 AssocSuggestion::MethodWithSelf { called: false } => {
65 "refer to the method with the fully-qualified path"
66 }
67 AssocSuggestion::AssocFn { called: true } => "call the associated function",
68 AssocSuggestion::AssocFn { called: false } => "refer to the associated function",
69 AssocSuggestion::AssocConst => "use the associated `const`",
70 AssocSuggestion::AssocType => "use the associated type",
71 }
72 }
73}
74
75fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
76 namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
77}
78
79fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
80 namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
81}
82
83fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
85 let variant_path = &suggestion.path;
86 let variant_path_string = path_names_to_string(variant_path);
87
88 let path_len = suggestion.path.segments.len();
89 let enum_path = ast::Path {
90 span: suggestion.path.span,
91 segments: suggestion.path.segments[0..path_len - 1].iter().cloned().collect(),
92 tokens: None,
93 };
94 let enum_path_string = path_names_to_string(&enum_path);
95
96 (variant_path_string, enum_path_string)
97}
98
99#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
101pub(super) struct MissingLifetime {
102 pub id: NodeId,
104 pub id_for_lint: NodeId,
111 pub span: Span,
113 pub kind: MissingLifetimeKind,
115 pub count: usize,
117}
118
119#[derive(Clone, Debug)]
122pub(super) struct ElisionFnParameter {
123 pub index: usize,
125 pub ident: Option<Ident>,
127 pub lifetime_count: usize,
129 pub span: Span,
131}
132
133#[derive(Debug)]
136pub(super) enum LifetimeElisionCandidate {
137 Ignore,
139 Named,
141 Missing(MissingLifetime),
142}
143
144#[derive(Debug)]
146struct BaseError {
147 msg: String,
148 fallback_label: String,
149 span: Span,
150 span_label: Option<(Span, &'static str)>,
151 could_be_expr: bool,
152 suggestion: Option<(Span, &'static str, String)>,
153 module: Option<DefId>,
154}
155
156#[derive(Debug)]
157enum TypoCandidate {
158 Typo(TypoSuggestion),
159 Shadowed(Res, Option<Span>),
160 None,
161}
162
163impl TypoCandidate {
164 fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
165 match self {
166 TypoCandidate::Typo(sugg) => Some(sugg),
167 TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,
168 }
169 }
170}
171
172impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
173 fn make_base_error(
174 &mut self,
175 path: &[Segment],
176 span: Span,
177 source: PathSource<'_>,
178 res: Option<Res>,
179 ) -> BaseError {
180 let mut expected = source.descr_expected();
182 let path_str = Segment::names_to_string(path);
183 let item_str = path.last().unwrap().ident;
184 if let Some(res) = res {
185 BaseError {
186 msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
187 fallback_label: format!("not a {expected}"),
188 span,
189 span_label: match res {
190 Res::Def(DefKind::TyParam, def_id) => {
191 Some((self.r.def_span(def_id), "found this type parameter"))
192 }
193 _ => None,
194 },
195 could_be_expr: match res {
196 Res::Def(DefKind::Fn, _) => {
197 self.r
199 .tcx
200 .sess
201 .source_map()
202 .span_to_snippet(span)
203 .is_ok_and(|snippet| snippet.ends_with(')'))
204 }
205 Res::Def(
206 DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
207 _,
208 )
209 | Res::SelfCtor(_)
210 | Res::PrimTy(_)
211 | Res::Local(_) => true,
212 _ => false,
213 },
214 suggestion: None,
215 module: None,
216 }
217 } else {
218 let mut span_label = None;
219 let item_ident = path.last().unwrap().ident;
220 let item_span = item_ident.span;
221 let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
222 debug!(?self.diag_metadata.current_impl_items);
223 debug!(?self.diag_metadata.current_function);
224 let suggestion = if self.current_trait_ref.is_none()
225 && let Some((fn_kind, _)) = self.diag_metadata.current_function
226 && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
227 && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = fn_kind
228 && let Some(items) = self.diag_metadata.current_impl_items
229 && let Some(item) = items.iter().find(|i| {
230 i.ident.name == item_str.name
231 && !sig.span.contains(item_span)
233 }) {
234 let sp = item_span.shrink_to_lo();
235
236 let field = match source {
239 PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {
240 expr.fields.iter().find(|f| f.ident == item_ident)
241 }
242 _ => None,
243 };
244 let pre = if let Some(field) = field
245 && field.is_shorthand
246 {
247 format!("{item_ident}: ")
248 } else {
249 String::new()
250 };
251 let is_call = match field {
254 Some(ast::ExprField { expr, .. }) => {
255 matches!(expr.kind, ExprKind::Call(..))
256 }
257 _ => matches!(
258 source,
259 PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),
260 ),
261 };
262
263 match &item.kind {
264 AssocItemKind::Fn(fn_)
265 if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>
266 {
267 span_label = Some((
271 item.ident.span,
272 "a method by that name is available on `Self` here",
273 ));
274 None
275 }
276 AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {
277 span_label = Some((
278 item.ident.span,
279 "an associated function by that name is available on `Self` here",
280 ));
281 None
282 }
283 AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {
284 Some((sp, "consider using the method on `Self`", format!("{pre}self.")))
285 }
286 AssocItemKind::Fn(_) => Some((
287 sp,
288 "consider using the associated function on `Self`",
289 format!("{pre}Self::"),
290 )),
291 AssocItemKind::Const(..) => Some((
292 sp,
293 "consider using the associated constant on `Self`",
294 format!("{pre}Self::"),
295 )),
296 _ => None,
297 }
298 } else {
299 None
300 };
301 (String::new(), "this scope".to_string(), None, suggestion)
302 } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
303 if self.r.tcx.sess.edition() > Edition::Edition2015 {
304 expected = "crate";
307 (String::new(), "the list of imported crates".to_string(), None, None)
308 } else {
309 (
310 String::new(),
311 "the crate root".to_string(),
312 Some(CRATE_DEF_ID.to_def_id()),
313 None,
314 )
315 }
316 } else if path.len() == 2 && path[0].ident.name == kw::Crate {
317 (String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)
318 } else {
319 let mod_path = &path[..path.len() - 1];
320 let mod_res = self.resolve_path(mod_path, Some(TypeNS), None);
321 let mod_prefix = match mod_res {
322 PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
323 _ => None,
324 };
325
326 let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);
327
328 let mod_prefix =
329 mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr())));
330
331 (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)
332 };
333
334 let (fallback_label, suggestion) = if path_str == "async"
335 && expected.starts_with("struct")
336 {
337 ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion)
338 } else {
339 let override_suggestion =
341 if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {
342 let item_typo = item_str.to_string().to_lowercase();
343 Some((item_span, "you may want to use a bool value instead", item_typo))
344 } else if item_str.as_str() == "printf" {
347 Some((
348 item_span,
349 "you may have meant to use the `print` macro",
350 "print!".to_owned(),
351 ))
352 } else {
353 suggestion
354 };
355 (format!("not found in {mod_str}"), override_suggestion)
356 };
357
358 BaseError {
359 msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
360 fallback_label,
361 span: item_span,
362 span_label,
363 could_be_expr: false,
364 suggestion,
365 module,
366 }
367 }
368 }
369
370 pub(crate) fn smart_resolve_partial_mod_path_errors(
378 &mut self,
379 prefix_path: &[Segment],
380 following_seg: Option<&Segment>,
381 ) -> Vec<ImportSuggestion> {
382 if let Some(segment) = prefix_path.last()
383 && let Some(following_seg) = following_seg
384 {
385 let candidates = self.r.lookup_import_candidates(
386 segment.ident,
387 Namespace::TypeNS,
388 &self.parent_scope,
389 &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),
390 );
391 candidates
393 .into_iter()
394 .filter(|candidate| {
395 if let Some(def_id) = candidate.did
396 && let Some(module) = self.r.get_module(def_id)
397 {
398 Some(def_id) != self.parent_scope.module.opt_def_id()
399 && self
400 .r
401 .resolutions(module)
402 .borrow()
403 .iter()
404 .any(|(key, _r)| key.ident.name == following_seg.ident.name)
405 } else {
406 false
407 }
408 })
409 .collect::<Vec<_>>()
410 } else {
411 Vec::new()
412 }
413 }
414
415 pub(crate) fn smart_resolve_report_errors(
418 &mut self,
419 path: &[Segment],
420 following_seg: Option<&Segment>,
421 span: Span,
422 source: PathSource<'_>,
423 res: Option<Res>,
424 ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
425 debug!(?res, ?source);
426 let base_error = self.make_base_error(path, span, source, res);
427
428 let code = source.error_code(res.is_some());
429 let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());
430 err.code(code);
431
432 self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
433 self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
434 self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
435
436 if let Some((span, label)) = base_error.span_label {
437 err.span_label(span, label);
438 }
439
440 if let Some(ref sugg) = base_error.suggestion {
441 err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
442 }
443
444 self.suggest_bare_struct_literal(&mut err);
445 self.suggest_changing_type_to_const_param(&mut err, res, source, span);
446 self.explain_functions_in_pattern(&mut err, res, source);
447
448 if self.suggest_pattern_match_with_let(&mut err, source, span) {
449 err.span_label(base_error.span, base_error.fallback_label);
451 return (err, Vec::new());
452 }
453
454 self.suggest_self_or_self_ref(&mut err, path, span);
455 self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
456 if self.suggest_self_ty(&mut err, source, path, span)
457 || self.suggest_self_value(&mut err, source, path, span)
458 {
459 return (err, Vec::new());
460 }
461
462 let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(
463 &mut err,
464 source,
465 path,
466 following_seg,
467 span,
468 res,
469 &base_error,
470 );
471 if found {
472 return (err, candidates);
473 }
474
475 if self.suggest_shadowed(&mut err, source, path, following_seg, span) {
476 candidates.clear();
478 }
479
480 let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
481 fallback |= self.suggest_typo(
482 &mut err,
483 source,
484 path,
485 following_seg,
486 span,
487 &base_error,
488 suggested_candidates,
489 );
490
491 if fallback {
492 err.span_label(base_error.span, base_error.fallback_label);
494 }
495 self.err_code_special_cases(&mut err, source, path, span);
496
497 if let Some(module) = base_error.module {
498 self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
499 }
500
501 (err, candidates)
502 }
503
504 fn detect_assoc_type_constraint_meant_as_path(
505 &self,
506 err: &mut Diag<'_>,
507 base_error: &BaseError,
508 ) {
509 let Some(ty) = self.diag_metadata.current_type_path else {
510 return;
511 };
512 let TyKind::Path(_, path) = &ty.kind else {
513 return;
514 };
515 for segment in &path.segments {
516 let Some(params) = &segment.args else {
517 continue;
518 };
519 let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else {
520 continue;
521 };
522 for param in ¶ms.args {
523 let ast::AngleBracketedArg::Constraint(constraint) = param else {
524 continue;
525 };
526 let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {
527 continue;
528 };
529 for bound in bounds {
530 let ast::GenericBound::Trait(trait_ref) = bound else {
531 continue;
532 };
533 if trait_ref.modifiers == ast::TraitBoundModifiers::NONE
534 && base_error.span == trait_ref.span
535 {
536 err.span_suggestion_verbose(
537 constraint.ident.span.between(trait_ref.span),
538 "you might have meant to write a path instead of an associated type bound",
539 "::",
540 Applicability::MachineApplicable,
541 );
542 }
543 }
544 }
545 }
546 }
547
548 fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {
549 if !self.self_type_is_available() {
550 return;
551 }
552 let Some(path_last_segment) = path.last() else { return };
553 let item_str = path_last_segment.ident;
554 if ["this", "my"].contains(&item_str.as_str()) {
556 err.span_suggestion_short(
557 span,
558 "you might have meant to use `self` here instead",
559 "self",
560 Applicability::MaybeIncorrect,
561 );
562 if !self.self_value_is_available(path[0].ident.span) {
563 if let Some((FnKind::Fn(_, _, _, ast::Fn { sig, .. }), fn_span)) =
564 &self.diag_metadata.current_function
565 {
566 let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
567 (param.span.shrink_to_lo(), "&self, ")
568 } else {
569 (
570 self.r
571 .tcx
572 .sess
573 .source_map()
574 .span_through_char(*fn_span, '(')
575 .shrink_to_hi(),
576 "&self",
577 )
578 };
579 err.span_suggestion_verbose(
580 span,
581 "if you meant to use `self`, you are also missing a `self` receiver \
582 argument",
583 sugg,
584 Applicability::MaybeIncorrect,
585 );
586 }
587 }
588 }
589 }
590
591 fn try_lookup_name_relaxed(
592 &mut self,
593 err: &mut Diag<'_>,
594 source: PathSource<'_>,
595 path: &[Segment],
596 following_seg: Option<&Segment>,
597 span: Span,
598 res: Option<Res>,
599 base_error: &BaseError,
600 ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {
601 let span = match following_seg {
602 Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {
603 path[0].ident.span.to(path[path.len() - 1].ident.span)
606 }
607 _ => span,
608 };
609 let mut suggested_candidates = FxHashSet::default();
610 let ident = path.last().unwrap().ident;
612 let is_expected = &|res| source.is_expected(res);
613 let ns = source.namespace();
614 let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
615 let path_str = Segment::names_to_string(path);
616 let ident_span = path.last().map_or(span, |ident| ident.ident.span);
617 let mut candidates = self
618 .r
619 .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
620 .into_iter()
621 .filter(|ImportSuggestion { did, .. }| {
622 match (did, res.and_then(|res| res.opt_def_id())) {
623 (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
624 _ => true,
625 }
626 })
627 .collect::<Vec<_>>();
628 let intrinsic_candidates: Vec<_> = candidates
631 .extract_if(.., |sugg| {
632 let path = path_names_to_string(&sugg.path);
633 path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
634 })
635 .collect();
636 if candidates.is_empty() {
637 candidates = intrinsic_candidates;
639 }
640 let crate_def_id = CRATE_DEF_ID.to_def_id();
641 if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
642 let mut enum_candidates: Vec<_> = self
643 .r
644 .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)
645 .into_iter()
646 .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
647 .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
648 .collect();
649 if !enum_candidates.is_empty() {
650 enum_candidates.sort();
651
652 let preamble = if res.is_none() {
655 let others = match enum_candidates.len() {
656 1 => String::new(),
657 2 => " and 1 other".to_owned(),
658 n => format!(" and {n} others"),
659 };
660 format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
661 } else {
662 String::new()
663 };
664 let msg = format!("{preamble}try using the variant's enum");
665
666 suggested_candidates.extend(
667 enum_candidates
668 .iter()
669 .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),
670 );
671 err.span_suggestions(
672 span,
673 msg,
674 enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),
675 Applicability::MachineApplicable,
676 );
677 }
678 }
679
680 let typo_sugg = self
682 .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
683 .to_opt_suggestion()
684 .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));
685 if let [segment] = path
686 && !matches!(source, PathSource::Delegation)
687 && self.self_type_is_available()
688 {
689 if let Some(candidate) =
690 self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
691 {
692 let self_is_available = self.self_value_is_available(segment.ident.span);
693 let pre = match source {
696 PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))
697 if expr
698 .fields
699 .iter()
700 .any(|f| f.ident == segment.ident && f.is_shorthand) =>
701 {
702 format!("{path_str}: ")
703 }
704 _ => String::new(),
705 };
706 match candidate {
707 AssocSuggestion::Field(field_span) => {
708 if self_is_available {
709 err.span_suggestion_verbose(
710 span.shrink_to_lo(),
711 "you might have meant to use the available field",
712 format!("{pre}self."),
713 Applicability::MachineApplicable,
714 );
715 } else {
716 err.span_label(field_span, "a field by that name exists in `Self`");
717 }
718 }
719 AssocSuggestion::MethodWithSelf { called } if self_is_available => {
720 let msg = if called {
721 "you might have meant to call the method"
722 } else {
723 "you might have meant to refer to the method"
724 };
725 err.span_suggestion_verbose(
726 span.shrink_to_lo(),
727 msg,
728 "self.",
729 Applicability::MachineApplicable,
730 );
731 }
732 AssocSuggestion::MethodWithSelf { .. }
733 | AssocSuggestion::AssocFn { .. }
734 | AssocSuggestion::AssocConst
735 | AssocSuggestion::AssocType => {
736 err.span_suggestion_verbose(
737 span.shrink_to_lo(),
738 format!("you might have meant to {}", candidate.action()),
739 "Self::",
740 Applicability::MachineApplicable,
741 );
742 }
743 }
744 self.r.add_typo_suggestion(err, typo_sugg, ident_span);
745 return (true, suggested_candidates, candidates);
746 }
747
748 if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
750 let mut args_snippet = String::new();
751 if let Some(args_span) = args_span {
752 if let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span) {
753 args_snippet = snippet;
754 }
755 }
756
757 err.span_suggestion(
758 call_span,
759 format!("try calling `{ident}` as a method"),
760 format!("self.{path_str}({args_snippet})"),
761 Applicability::MachineApplicable,
762 );
763 return (true, suggested_candidates, candidates);
764 }
765 }
766
767 if let Some(res) = res {
769 if self.smart_resolve_context_dependent_help(
770 err,
771 span,
772 source,
773 path,
774 res,
775 &path_str,
776 &base_error.fallback_label,
777 ) {
778 self.r.add_typo_suggestion(err, typo_sugg, ident_span);
780 return (true, suggested_candidates, candidates);
781 }
782 }
783
784 if let Some(rib) = &self.last_block_rib
786 && let RibKind::Normal = rib.kind
787 {
788 for (ident, &res) in &rib.bindings {
789 if let Res::Local(_) = res
790 && path.len() == 1
791 && ident.span.eq_ctxt(path[0].ident.span)
792 && ident.name == path[0].ident.name
793 {
794 err.span_help(
795 ident.span,
796 format!("the binding `{path_str}` is available in a different scope in the same function"),
797 );
798 return (true, suggested_candidates, candidates);
799 }
800 }
801 }
802
803 if candidates.is_empty() {
804 candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
805 }
806
807 (false, suggested_candidates, candidates)
808 }
809
810 fn suggest_trait_and_bounds(
811 &mut self,
812 err: &mut Diag<'_>,
813 source: PathSource<'_>,
814 res: Option<Res>,
815 span: Span,
816 base_error: &BaseError,
817 ) -> bool {
818 let is_macro =
819 base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
820 let mut fallback = false;
821
822 if let (
823 PathSource::Trait(AliasPossibility::Maybe),
824 Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
825 false,
826 ) = (source, res, is_macro)
827 {
828 if let Some(bounds @ [first_bound, .., last_bound]) =
829 self.diag_metadata.current_trait_object
830 {
831 fallback = true;
832 let spans: Vec<Span> = bounds
833 .iter()
834 .map(|bound| bound.span())
835 .filter(|&sp| sp != base_error.span)
836 .collect();
837
838 let start_span = first_bound.span();
839 let end_span = last_bound.span();
841 let last_bound_span = spans.last().cloned().unwrap();
843 let mut multi_span: MultiSpan = spans.clone().into();
844 for sp in spans {
845 let msg = if sp == last_bound_span {
846 format!(
847 "...because of {these} bound{s}",
848 these = pluralize!("this", bounds.len() - 1),
849 s = pluralize!(bounds.len() - 1),
850 )
851 } else {
852 String::new()
853 };
854 multi_span.push_span_label(sp, msg);
855 }
856 multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
857 err.span_help(
858 multi_span,
859 "`+` is used to constrain a \"trait object\" type with lifetimes or \
860 auto-traits; structs and enums can't be bound in that way",
861 );
862 if bounds.iter().all(|bound| match bound {
863 ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
864 ast::GenericBound::Trait(tr) => tr.span == base_error.span,
865 }) {
866 let mut sugg = vec![];
867 if base_error.span != start_span {
868 sugg.push((start_span.until(base_error.span), String::new()));
869 }
870 if base_error.span != end_span {
871 sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
872 }
873
874 err.multipart_suggestion(
875 "if you meant to use a type and not a trait here, remove the bounds",
876 sugg,
877 Applicability::MaybeIncorrect,
878 );
879 }
880 }
881 }
882
883 fallback |= self.restrict_assoc_type_in_where_clause(span, err);
884 fallback
885 }
886
887 fn suggest_typo(
888 &mut self,
889 err: &mut Diag<'_>,
890 source: PathSource<'_>,
891 path: &[Segment],
892 following_seg: Option<&Segment>,
893 span: Span,
894 base_error: &BaseError,
895 suggested_candidates: FxHashSet<String>,
896 ) -> bool {
897 let is_expected = &|res| source.is_expected(res);
898 let ident_span = path.last().map_or(span, |ident| ident.ident.span);
899 let typo_sugg =
900 self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
901 let mut fallback = false;
902 let typo_sugg = typo_sugg
903 .to_opt_suggestion()
904 .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));
905 if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
906 fallback = true;
907 match self.diag_metadata.current_let_binding {
908 Some((pat_sp, Some(ty_sp), None))
909 if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
910 {
911 err.span_suggestion_short(
912 pat_sp.between(ty_sp),
913 "use `=` if you meant to assign",
914 " = ",
915 Applicability::MaybeIncorrect,
916 );
917 }
918 _ => {}
919 }
920
921 let suggestion = self.get_single_associated_item(path, &source, is_expected);
923 self.r.add_typo_suggestion(err, suggestion, ident_span);
924 }
925
926 if self.let_binding_suggestion(err, ident_span) {
927 fallback = false;
928 }
929
930 fallback
931 }
932
933 fn suggest_shadowed(
934 &mut self,
935 err: &mut Diag<'_>,
936 source: PathSource<'_>,
937 path: &[Segment],
938 following_seg: Option<&Segment>,
939 span: Span,
940 ) -> bool {
941 let is_expected = &|res| source.is_expected(res);
942 let typo_sugg =
943 self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
944 let is_in_same_file = &|sp1, sp2| {
945 let source_map = self.r.tcx.sess.source_map();
946 let file1 = source_map.span_to_filename(sp1);
947 let file2 = source_map.span_to_filename(sp2);
948 file1 == file2
949 };
950 if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
955 && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))
956 {
957 err.span_label(
958 sugg_span,
959 format!("you might have meant to refer to this {}", res.descr()),
960 );
961 return true;
962 }
963 false
964 }
965
966 fn err_code_special_cases(
967 &mut self,
968 err: &mut Diag<'_>,
969 source: PathSource<'_>,
970 path: &[Segment],
971 span: Span,
972 ) {
973 if let Some(err_code) = err.code {
974 if err_code == E0425 {
975 for label_rib in &self.label_ribs {
976 for (label_ident, node_id) in &label_rib.bindings {
977 let ident = path.last().unwrap().ident;
978 if format!("'{ident}") == label_ident.to_string() {
979 err.span_label(label_ident.span, "a label with a similar name exists");
980 if let PathSource::Expr(Some(Expr {
981 kind: ExprKind::Break(None, Some(_)),
982 ..
983 })) = source
984 {
985 err.span_suggestion(
986 span,
987 "use the similarly named label",
988 label_ident.name,
989 Applicability::MaybeIncorrect,
990 );
991 self.diag_metadata.unused_labels.remove(node_id);
993 }
994 }
995 }
996 }
997 } else if err_code == E0412 {
998 if let Some(correct) = Self::likely_rust_type(path) {
999 err.span_suggestion(
1000 span,
1001 "perhaps you intended to use this type",
1002 correct,
1003 Applicability::MaybeIncorrect,
1004 );
1005 }
1006 }
1007 }
1008 }
1009
1010 fn suggest_self_ty(
1012 &mut self,
1013 err: &mut Diag<'_>,
1014 source: PathSource<'_>,
1015 path: &[Segment],
1016 span: Span,
1017 ) -> bool {
1018 if !is_self_type(path, source.namespace()) {
1019 return false;
1020 }
1021 err.code(E0411);
1022 err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
1023 if let Some(item_kind) = self.diag_metadata.current_item {
1024 if !item_kind.ident.span.is_dummy() {
1025 err.span_label(
1026 item_kind.ident.span,
1027 format!(
1028 "`Self` not allowed in {} {}",
1029 item_kind.kind.article(),
1030 item_kind.kind.descr()
1031 ),
1032 );
1033 }
1034 }
1035 true
1036 }
1037
1038 fn suggest_self_value(
1039 &mut self,
1040 err: &mut Diag<'_>,
1041 source: PathSource<'_>,
1042 path: &[Segment],
1043 span: Span,
1044 ) -> bool {
1045 if !is_self_value(path, source.namespace()) {
1046 return false;
1047 }
1048
1049 debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
1050 err.code(E0424);
1051 err.span_label(
1052 span,
1053 match source {
1054 PathSource::Pat => {
1055 "`self` value is a keyword and may not be bound to variables or shadowed"
1056 }
1057 _ => "`self` value is a keyword only available in methods with a `self` parameter",
1058 },
1059 );
1060 let is_assoc_fn = self.self_type_is_available();
1061 let self_from_macro = "a `self` parameter, but a macro invocation can only \
1062 access identifiers it receives from parameters";
1063 if let Some((fn_kind, span)) = &self.diag_metadata.current_function {
1064 if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
1068 err.span_label(*span, format!("this function has {self_from_macro}"));
1069 } else {
1070 let doesnt = if is_assoc_fn {
1071 let (span, sugg) = fn_kind
1072 .decl()
1073 .inputs
1074 .get(0)
1075 .map(|p| (p.span.shrink_to_lo(), "&self, "))
1076 .unwrap_or_else(|| {
1077 let span = fn_kind
1080 .ident()
1081 .map_or(*span, |ident| span.with_lo(ident.span.hi()));
1082 (
1083 self.r
1084 .tcx
1085 .sess
1086 .source_map()
1087 .span_through_char(span, '(')
1088 .shrink_to_hi(),
1089 "&self",
1090 )
1091 });
1092 err.span_suggestion_verbose(
1093 span,
1094 "add a `self` receiver parameter to make the associated `fn` a method",
1095 sugg,
1096 Applicability::MaybeIncorrect,
1097 );
1098 "doesn't"
1099 } else {
1100 "can't"
1101 };
1102 if let Some(ident) = fn_kind.ident() {
1103 err.span_label(
1104 ident.span,
1105 format!("this function {doesnt} have a `self` parameter"),
1106 );
1107 }
1108 }
1109 } else if let Some(item_kind) = self.diag_metadata.current_item {
1110 if matches!(item_kind.kind, ItemKind::Delegation(..)) {
1111 err.span_label(item_kind.span, format!("delegation supports {self_from_macro}"));
1112 } else {
1113 err.span_label(
1114 item_kind.ident.span,
1115 format!(
1116 "`self` not allowed in {} {}",
1117 item_kind.kind.article(),
1118 item_kind.kind.descr()
1119 ),
1120 );
1121 }
1122 }
1123 true
1124 }
1125
1126 fn detect_missing_binding_available_from_pattern(
1127 &mut self,
1128 err: &mut Diag<'_>,
1129 path: &[Segment],
1130 following_seg: Option<&Segment>,
1131 ) {
1132 let [segment] = path else { return };
1133 let None = following_seg else { return };
1134 for rib in self.ribs[ValueNS].iter().rev() {
1135 for (def_id, spans) in &rib.patterns_with_skipped_bindings {
1136 if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)
1137 && let Some(fields) = self.r.field_idents(*def_id)
1138 {
1139 for field in fields {
1140 if field.name == segment.ident.name {
1141 if spans.iter().all(|(_, had_error)| had_error.is_err()) {
1142 let multispan: MultiSpan =
1145 spans.iter().map(|(s, _)| *s).collect::<Vec<_>>().into();
1146 err.span_note(
1147 multispan,
1148 "this pattern had a recovered parse error which likely lost \
1149 the expected fields",
1150 );
1151 err.downgrade_to_delayed_bug();
1152 }
1153 let ty = self.r.tcx.item_name(*def_id);
1154 for (span, _) in spans {
1155 err.span_label(
1156 *span,
1157 format!(
1158 "this pattern doesn't include `{field}`, which is \
1159 available in `{ty}`",
1160 ),
1161 );
1162 }
1163 }
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 fn suggest_at_operator_in_slice_pat_with_range(
1171 &mut self,
1172 err: &mut Diag<'_>,
1173 path: &[Segment],
1174 ) {
1175 let Some(pat) = self.diag_metadata.current_pat else { return };
1176 let (bound, side, range) = match &pat.kind {
1177 ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),
1178 ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),
1179 _ => return,
1180 };
1181 if let ExprKind::Path(None, range_path) = &bound.kind
1182 && let [segment] = &range_path.segments[..]
1183 && let [s] = path
1184 && segment.ident == s.ident
1185 && segment.ident.span.eq_ctxt(range.span)
1186 {
1187 let (span, snippet) = match side {
1190 Side::Start => (segment.ident.span.between(range.span), " @ ".into()),
1191 Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),
1192 };
1193 err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
1194 span,
1195 ident: segment.ident,
1196 snippet,
1197 });
1198 }
1199
1200 enum Side {
1201 Start,
1202 End,
1203 }
1204 }
1205
1206 fn suggest_swapping_misplaced_self_ty_and_trait(
1207 &mut self,
1208 err: &mut Diag<'_>,
1209 source: PathSource<'_>,
1210 res: Option<Res>,
1211 span: Span,
1212 ) {
1213 if let Some((trait_ref, self_ty)) =
1214 self.diag_metadata.currently_processing_impl_trait.clone()
1215 && let TyKind::Path(_, self_ty_path) = &self_ty.kind
1216 && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1217 self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
1218 && let ModuleKind::Def(DefKind::Trait, ..) = module.kind
1219 && trait_ref.path.span == span
1220 && let PathSource::Trait(_) = source
1221 && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
1222 && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)
1223 && let Ok(trait_ref_str) =
1224 self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)
1225 {
1226 err.multipart_suggestion(
1227 "`impl` items mention the trait being implemented first and the type it is being implemented for second",
1228 vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
1229 Applicability::MaybeIncorrect,
1230 );
1231 }
1232 }
1233
1234 fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) {
1235 if let Some(span) = self.diag_metadata.current_block_could_be_bare_struct_literal {
1236 err.multipart_suggestion(
1237 "you might have meant to write a `struct` literal",
1238 vec![
1239 (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
1240 (span.shrink_to_hi(), "}".to_string()),
1241 ],
1242 Applicability::HasPlaceholders,
1243 );
1244 }
1245 }
1246
1247 fn explain_functions_in_pattern(
1248 &mut self,
1249 err: &mut Diag<'_>,
1250 res: Option<Res>,
1251 source: PathSource<'_>,
1252 ) {
1253 let PathSource::TupleStruct(_, _) = source else { return };
1254 let Some(Res::Def(DefKind::Fn, _)) = res else { return };
1255 err.primary_message("expected a pattern, found a function call");
1256 err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");
1257 }
1258
1259 fn suggest_changing_type_to_const_param(
1260 &mut self,
1261 err: &mut Diag<'_>,
1262 res: Option<Res>,
1263 source: PathSource<'_>,
1264 span: Span,
1265 ) {
1266 let PathSource::Trait(_) = source else { return };
1267
1268 let applicability = match res {
1270 Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
1271 Applicability::MachineApplicable
1272 }
1273 Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
1277 if self.r.tcx.features().adt_const_params() =>
1278 {
1279 Applicability::MaybeIncorrect
1280 }
1281 _ => return,
1282 };
1283
1284 let Some(item) = self.diag_metadata.current_item else { return };
1285 let Some(generics) = item.kind.generics() else { return };
1286
1287 let param = generics.params.iter().find_map(|param| {
1288 if let [bound] = &*param.bounds
1290 && let ast::GenericBound::Trait(tref) = bound
1291 && tref.modifiers == ast::TraitBoundModifiers::NONE
1292 && tref.span == span
1293 && param.ident.span.eq_ctxt(span)
1294 {
1295 Some(param.ident.span)
1296 } else {
1297 None
1298 }
1299 });
1300
1301 if let Some(param) = param {
1302 err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
1303 span: param.shrink_to_lo(),
1304 applicability,
1305 });
1306 }
1307 }
1308
1309 fn suggest_pattern_match_with_let(
1310 &mut self,
1311 err: &mut Diag<'_>,
1312 source: PathSource<'_>,
1313 span: Span,
1314 ) -> bool {
1315 if let PathSource::Expr(_) = source
1316 && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =
1317 self.diag_metadata.in_if_condition
1318 {
1319 if lhs.is_approximately_pattern() && lhs.span.contains(span) {
1323 err.span_suggestion_verbose(
1324 expr_span.shrink_to_lo(),
1325 "you might have meant to use pattern matching",
1326 "let ",
1327 Applicability::MaybeIncorrect,
1328 );
1329 return true;
1330 }
1331 }
1332 false
1333 }
1334
1335 fn get_single_associated_item(
1336 &mut self,
1337 path: &[Segment],
1338 source: &PathSource<'_>,
1339 filter_fn: &impl Fn(Res) -> bool,
1340 ) -> Option<TypoSuggestion> {
1341 if let crate::PathSource::TraitItem(_) = source {
1342 let mod_path = &path[..path.len() - 1];
1343 if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1344 self.resolve_path(mod_path, None, None)
1345 {
1346 let resolutions = self.r.resolutions(module).borrow();
1347 let targets: Vec<_> =
1348 resolutions
1349 .iter()
1350 .filter_map(|(key, resolution)| {
1351 resolution.borrow().binding.map(|binding| binding.res()).and_then(
1352 |res| if filter_fn(res) { Some((key, res)) } else { None },
1353 )
1354 })
1355 .collect();
1356 if let [target] = targets.as_slice() {
1357 return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
1358 }
1359 }
1360 }
1361 None
1362 }
1363
1364 fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool {
1366 let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
1368 kind:
1369 ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
1370 bounded_ty,
1371 bound_generic_params,
1372 bounds,
1373 }),
1374 span,
1375 ..
1376 }) = self.diag_metadata.current_where_predicate
1377 {
1378 if !bound_generic_params.is_empty() {
1379 return false;
1380 }
1381 (bounded_ty, bounds, span)
1382 } else {
1383 return false;
1384 };
1385
1386 let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind {
1388 let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
1390 return false;
1391 };
1392 if !matches!(
1393 partial_res.full_res(),
1394 Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
1395 ) {
1396 return false;
1397 }
1398 (&qself.ty, qself.position, path)
1399 } else {
1400 return false;
1401 };
1402
1403 let peeled_ty = ty.peel_refs();
1404 if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind {
1405 let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
1407 return false;
1408 };
1409 if !matches!(
1410 partial_res.full_res(),
1411 Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
1412 ) {
1413 return false;
1414 }
1415 if let (
1416 [ast::PathSegment { args: None, .. }],
1417 [ast::GenericBound::Trait(poly_trait_ref)],
1418 ) = (&type_param_path.segments[..], &bounds[..])
1419 && poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE
1420 {
1421 if let [ast::PathSegment { ident, args: None, .. }] =
1422 &poly_trait_ref.trait_ref.path.segments[..]
1423 {
1424 if ident.span == span {
1425 let Some(new_where_bound_predicate) =
1426 mk_where_bound_predicate(path, poly_trait_ref, ty)
1427 else {
1428 return false;
1429 };
1430 err.span_suggestion_verbose(
1431 *where_span,
1432 format!("constrain the associated type to `{ident}`"),
1433 where_bound_predicate_to_string(&new_where_bound_predicate),
1434 Applicability::MaybeIncorrect,
1435 );
1436 }
1437 return true;
1438 }
1439 }
1440 }
1441 false
1442 }
1443
1444 fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
1447 let mut has_self_arg = None;
1448 if let PathSource::Expr(Some(parent)) = source
1449 && let ExprKind::Call(_, args) = &parent.kind
1450 && !args.is_empty()
1451 {
1452 let mut expr_kind = &args[0].kind;
1453 loop {
1454 match expr_kind {
1455 ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
1456 if arg_name.segments[0].ident.name == kw::SelfLower {
1457 let call_span = parent.span;
1458 let tail_args_span = if args.len() > 1 {
1459 Some(Span::new(
1460 args[1].span.lo(),
1461 args.last().unwrap().span.hi(),
1462 call_span.ctxt(),
1463 None,
1464 ))
1465 } else {
1466 None
1467 };
1468 has_self_arg = Some((call_span, tail_args_span));
1469 }
1470 break;
1471 }
1472 ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
1473 _ => break,
1474 }
1475 }
1476 }
1477 has_self_arg
1478 }
1479
1480 fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
1481 let sm = self.r.tcx.sess.source_map();
1486 if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
1487 let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
1490 let closing_brace = close_brace_span.map(|sp| span.to(sp));
1491 (true, closing_brace)
1492 } else {
1493 (false, None)
1494 }
1495 }
1496
1497 fn smart_resolve_context_dependent_help(
1501 &mut self,
1502 err: &mut Diag<'_>,
1503 span: Span,
1504 source: PathSource<'_>,
1505 path: &[Segment],
1506 res: Res,
1507 path_str: &str,
1508 fallback_label: &str,
1509 ) -> bool {
1510 let ns = source.namespace();
1511 let is_expected = &|res| source.is_expected(res);
1512
1513 let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
1514 const MESSAGE: &str = "use the path separator to refer to an item";
1515
1516 let (lhs_span, rhs_span) = match &expr.kind {
1517 ExprKind::Field(base, ident) => (base.span, ident.span),
1518 ExprKind::MethodCall(box MethodCall { receiver, span, .. }) => {
1519 (receiver.span, *span)
1520 }
1521 _ => return false,
1522 };
1523
1524 if lhs_span.eq_ctxt(rhs_span) {
1525 err.span_suggestion_verbose(
1526 lhs_span.between(rhs_span),
1527 MESSAGE,
1528 "::",
1529 Applicability::MaybeIncorrect,
1530 );
1531 true
1532 } else if kind == DefKind::Struct
1533 && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
1534 && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
1535 {
1536 err.span_suggestion_verbose(
1540 lhs_source_span.until(rhs_span),
1541 MESSAGE,
1542 format!("<{snippet}>::"),
1543 Applicability::MaybeIncorrect,
1544 );
1545 true
1546 } else {
1547 false
1553 }
1554 };
1555
1556 let find_span = |source: &PathSource<'_>, err: &mut Diag<'_>| {
1557 match source {
1558 PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
1559 | PathSource::TupleStruct(span, _) => {
1560 err.span(*span);
1563 *span
1564 }
1565 _ => span,
1566 }
1567 };
1568
1569 let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| {
1570 let (followed_by_brace, closing_brace) = this.followed_by_brace(span);
1571
1572 match source {
1573 PathSource::Expr(Some(
1574 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
1575 )) if path_sep(this, err, parent, DefKind::Struct) => {}
1576 PathSource::Expr(
1577 None
1578 | Some(Expr {
1579 kind:
1580 ExprKind::Path(..)
1581 | ExprKind::Binary(..)
1582 | ExprKind::Unary(..)
1583 | ExprKind::If(..)
1584 | ExprKind::While(..)
1585 | ExprKind::ForLoop { .. }
1586 | ExprKind::Match(..),
1587 ..
1588 }),
1589 ) if followed_by_brace => {
1590 if let Some(sp) = closing_brace {
1591 err.span_label(span, fallback_label.to_string());
1592 err.multipart_suggestion(
1593 "surround the struct literal with parentheses",
1594 vec![
1595 (sp.shrink_to_lo(), "(".to_string()),
1596 (sp.shrink_to_hi(), ")".to_string()),
1597 ],
1598 Applicability::MaybeIncorrect,
1599 );
1600 } else {
1601 err.span_label(
1602 span, format!(
1604 "you might want to surround a struct literal with parentheses: \
1605 `({path_str} {{ /* fields */ }})`?"
1606 ),
1607 );
1608 }
1609 }
1610 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1611 let span = find_span(&source, err);
1612 err.span_label(this.r.def_span(def_id), format!("`{path_str}` defined here"));
1613
1614 let (tail, descr, applicability, old_fields) = match source {
1615 PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
1616 PathSource::TupleStruct(_, args) => (
1617 "",
1618 "pattern",
1619 Applicability::MachineApplicable,
1620 Some(
1621 args.iter()
1622 .map(|a| this.r.tcx.sess.source_map().span_to_snippet(*a).ok())
1623 .collect::<Vec<Option<String>>>(),
1624 ),
1625 ),
1626 _ => (": val", "literal", Applicability::HasPlaceholders, None),
1627 };
1628
1629 if !this.has_private_fields(def_id) {
1630 let fields = this.r.field_idents(def_id);
1633 let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty());
1634 let (fields, applicability) = match fields {
1635 Some(fields) => {
1636 let fields = if let Some(old_fields) = old_fields {
1637 fields
1638 .iter()
1639 .enumerate()
1640 .map(|(idx, new)| (new, old_fields.get(idx)))
1641 .map(|(new, old)| {
1642 if let Some(Some(old)) = old
1643 && new.as_str() != old
1644 {
1645 format!("{new}: {old}")
1646 } else {
1647 new.to_string()
1648 }
1649 })
1650 .collect::<Vec<String>>()
1651 } else {
1652 fields
1653 .iter()
1654 .map(|f| format!("{f}{tail}"))
1655 .collect::<Vec<String>>()
1656 };
1657
1658 (fields.join(", "), applicability)
1659 }
1660 None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
1661 };
1662 let pad = if has_fields { " " } else { "" };
1663 err.span_suggestion(
1664 span,
1665 format!("use struct {descr} syntax instead"),
1666 format!("{path_str} {{{pad}{fields}{pad}}}"),
1667 applicability,
1668 );
1669 }
1670 if let PathSource::Expr(Some(Expr {
1671 kind: ExprKind::Call(path, ref args),
1672 span: call_span,
1673 ..
1674 })) = source
1675 {
1676 this.suggest_alternative_construction_methods(
1677 def_id,
1678 err,
1679 path.span,
1680 *call_span,
1681 &args[..],
1682 );
1683 }
1684 }
1685 _ => {
1686 err.span_label(span, fallback_label.to_string());
1687 }
1688 }
1689 };
1690
1691 match (res, source) {
1692 (
1693 Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
1694 PathSource::Expr(Some(Expr {
1695 kind: ExprKind::Index(..) | ExprKind::Call(..), ..
1696 }))
1697 | PathSource::Struct,
1698 ) => {
1699 let suggestable = def_id.is_local()
1701 || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
1702
1703 err.span_label(span, fallback_label.to_string());
1704
1705 if path
1707 .last()
1708 .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
1709 && suggestable
1710 {
1711 err.span_suggestion_verbose(
1712 span.shrink_to_hi(),
1713 "use `!` to invoke the macro",
1714 "!",
1715 Applicability::MaybeIncorrect,
1716 );
1717 }
1718
1719 if path_str == "try" && span.is_rust_2015() {
1720 err.note("if you want the `try` keyword, you need Rust 2018 or later");
1721 }
1722 }
1723 (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
1724 err.span_label(span, fallback_label.to_string());
1725 }
1726 (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
1727 err.span_label(span, "type aliases cannot be used as traits");
1728 if self.r.tcx.sess.is_nightly_build() {
1729 let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
1730 `type` alias";
1731 let span = self.r.def_span(def_id);
1732 if let Ok(snip) = self.r.tcx.sess.source_map().span_to_snippet(span) {
1733 let snip = snip.replacen("type", "trait", 1);
1736 err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect);
1737 } else {
1738 err.span_help(span, msg);
1739 }
1740 }
1741 }
1742 (
1743 Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
1744 PathSource::Expr(Some(parent)),
1745 ) => {
1746 if !path_sep(self, err, parent, kind) {
1747 return false;
1748 }
1749 }
1750 (
1751 Res::Def(DefKind::Enum, def_id),
1752 PathSource::TupleStruct(..) | PathSource::Expr(..),
1753 ) => {
1754 self.suggest_using_enum_variant(err, source, def_id, span);
1755 }
1756 (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
1757 let struct_ctor = match def_id.as_local() {
1758 Some(def_id) => self.r.struct_constructors.get(&def_id).cloned(),
1759 None => {
1760 let ctor = self.r.cstore().ctor_untracked(def_id);
1761 ctor.map(|(ctor_kind, ctor_def_id)| {
1762 let ctor_res =
1763 Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
1764 let ctor_vis = self.r.tcx.visibility(ctor_def_id);
1765 let field_visibilities = self
1766 .r
1767 .tcx
1768 .associated_item_def_ids(def_id)
1769 .iter()
1770 .map(|field_id| self.r.tcx.visibility(field_id))
1771 .collect();
1772 (ctor_res, ctor_vis, field_visibilities)
1773 })
1774 }
1775 };
1776
1777 let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor {
1778 if let PathSource::Expr(Some(parent)) = source {
1779 if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
1780 bad_struct_syntax_suggestion(self, def_id);
1781 return true;
1782 }
1783 }
1784 struct_ctor
1785 } else {
1786 bad_struct_syntax_suggestion(self, def_id);
1787 return true;
1788 };
1789
1790 let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
1791 if !is_expected(ctor_def) || is_accessible {
1792 return true;
1793 }
1794
1795 let field_spans = match source {
1796 PathSource::TupleStruct(_, pattern_spans) => {
1798 err.primary_message(
1799 "cannot match against a tuple struct which contains private fields",
1800 );
1801
1802 Some(Vec::from(pattern_spans))
1804 }
1805 PathSource::Expr(Some(Expr {
1807 kind: ExprKind::Call(path, ref args),
1808 span: call_span,
1809 ..
1810 })) => {
1811 err.primary_message(
1812 "cannot initialize a tuple struct which contains private fields",
1813 );
1814 self.suggest_alternative_construction_methods(
1815 def_id,
1816 err,
1817 path.span,
1818 *call_span,
1819 &args[..],
1820 );
1821 self.r
1823 .field_idents(def_id)
1824 .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1825 }
1826 _ => None,
1827 };
1828
1829 if let Some(spans) =
1830 field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
1831 {
1832 let non_visible_spans: Vec<Span> = iter::zip(&fields, &spans)
1833 .filter(|(vis, _)| {
1834 !self.r.is_accessible_from(**vis, self.parent_scope.module)
1835 })
1836 .map(|(_, span)| *span)
1837 .collect();
1838
1839 if non_visible_spans.len() > 0 {
1840 if let Some(fields) = self.r.field_visibility_spans.get(&def_id) {
1841 err.multipart_suggestion_verbose(
1842 format!(
1843 "consider making the field{} publicly accessible",
1844 pluralize!(fields.len())
1845 ),
1846 fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
1847 Applicability::MaybeIncorrect,
1848 );
1849 }
1850
1851 let mut m: MultiSpan = non_visible_spans.clone().into();
1852 non_visible_spans
1853 .into_iter()
1854 .for_each(|s| m.push_span_label(s, "private field"));
1855 err.span_note(m, "constructor is not visible here due to private fields");
1856 }
1857
1858 return true;
1859 }
1860
1861 err.span_label(span, "constructor is not visible here due to private fields");
1862 }
1863 (Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => {
1864 bad_struct_syntax_suggestion(self, def_id);
1865 }
1866 (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
1867 match source {
1868 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1869 let span = find_span(&source, err);
1870 err.span_label(
1871 self.r.def_span(def_id),
1872 format!("`{path_str}` defined here"),
1873 );
1874 err.span_suggestion(
1875 span,
1876 "use this syntax instead",
1877 path_str,
1878 Applicability::MaybeIncorrect,
1879 );
1880 }
1881 _ => return false,
1882 }
1883 }
1884 (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => {
1885 let def_id = self.r.tcx.parent(ctor_def_id);
1886 err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
1887 let fields = self.r.field_idents(def_id).map_or_else(
1888 || "/* fields */".to_string(),
1889 |field_ids| vec!["_"; field_ids.len()].join(", "),
1890 );
1891 err.span_suggestion(
1892 span,
1893 "use the tuple variant pattern syntax instead",
1894 format!("{path_str}({fields})"),
1895 Applicability::HasPlaceholders,
1896 );
1897 }
1898 (Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => {
1899 err.span_label(span, fallback_label.to_string());
1900 err.note("can't use `Self` as a constructor, you must use the implemented struct");
1901 }
1902 (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
1903 err.note("can't use a type alias as a constructor");
1904 }
1905 _ => return false,
1906 }
1907 true
1908 }
1909
1910 fn suggest_alternative_construction_methods(
1911 &mut self,
1912 def_id: DefId,
1913 err: &mut Diag<'_>,
1914 path_span: Span,
1915 call_span: Span,
1916 args: &[P<Expr>],
1917 ) {
1918 if def_id.is_local() {
1919 return;
1921 }
1922 let mut items = self
1925 .r
1926 .tcx
1927 .inherent_impls(def_id)
1928 .iter()
1929 .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
1930 .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
1932 .filter_map(|item| {
1933 let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
1935 let ret_ty = fn_sig.output().skip_binder();
1937 let ty::Adt(def, _args) = ret_ty.kind() else {
1938 return None;
1939 };
1940 let input_len = fn_sig.inputs().skip_binder().len();
1941 if def.did() != def_id {
1942 return None;
1943 }
1944 let order = !item.name.as_str().starts_with("new");
1945 Some((order, item.name, input_len))
1946 })
1947 .collect::<Vec<_>>();
1948 items.sort_by_key(|(order, _, _)| *order);
1949 let suggestion = |name, args| {
1950 format!(
1951 "::{name}({})",
1952 std::iter::repeat("_").take(args).collect::<Vec<_>>().join(", ")
1953 )
1954 };
1955 match &items[..] {
1956 [] => {}
1957 [(_, name, len)] if *len == args.len() => {
1958 err.span_suggestion_verbose(
1959 path_span.shrink_to_hi(),
1960 format!("you might have meant to use the `{name}` associated function",),
1961 format!("::{name}"),
1962 Applicability::MaybeIncorrect,
1963 );
1964 }
1965 [(_, name, len)] => {
1966 err.span_suggestion_verbose(
1967 path_span.shrink_to_hi().with_hi(call_span.hi()),
1968 format!("you might have meant to use the `{name}` associated function",),
1969 suggestion(name, *len),
1970 Applicability::MaybeIncorrect,
1971 );
1972 }
1973 _ => {
1974 err.span_suggestions_with_style(
1975 path_span.shrink_to_hi().with_hi(call_span.hi()),
1976 "you might have meant to use an associated function to build this type",
1977 items.iter().map(|(_, name, len)| suggestion(name, *len)),
1978 Applicability::MaybeIncorrect,
1979 SuggestionStyle::ShowAlways,
1980 );
1981 }
1982 }
1983 let default_trait = self
1991 .r
1992 .lookup_import_candidates(
1993 Ident::with_dummy_span(sym::Default),
1994 Namespace::TypeNS,
1995 &self.parent_scope,
1996 &|res: Res| matches!(res, Res::Def(DefKind::Trait, _)),
1997 )
1998 .iter()
1999 .filter_map(|candidate| candidate.did)
2000 .find(|did| {
2001 self.r
2002 .tcx
2003 .get_attrs(*did, sym::rustc_diagnostic_item)
2004 .any(|attr| attr.value_str() == Some(sym::Default))
2005 });
2006 let Some(default_trait) = default_trait else {
2007 return;
2008 };
2009 if self
2010 .r
2011 .extern_crate_map
2012 .iter()
2013 .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait)))
2015 .filter_map(|(_, simplified_self_ty)| *simplified_self_ty)
2016 .filter_map(|simplified_self_ty| match simplified_self_ty {
2017 SimplifiedType::Adt(did) => Some(did),
2018 _ => None,
2019 })
2020 .any(|did| did == def_id)
2021 {
2022 err.multipart_suggestion(
2023 "consider using the `Default` trait",
2024 vec![
2025 (path_span.shrink_to_lo(), "<".to_string()),
2026 (
2027 path_span.shrink_to_hi().with_hi(call_span.hi()),
2028 " as std::default::Default>::default()".to_string(),
2029 ),
2030 ],
2031 Applicability::MaybeIncorrect,
2032 );
2033 }
2034 }
2035
2036 fn has_private_fields(&self, def_id: DefId) -> bool {
2037 let fields = match def_id.as_local() {
2038 Some(def_id) => self.r.struct_constructors.get(&def_id).cloned().map(|(_, _, f)| f),
2039 None => Some(
2040 self.r
2041 .tcx
2042 .associated_item_def_ids(def_id)
2043 .iter()
2044 .map(|field_id| self.r.tcx.visibility(field_id))
2045 .collect(),
2046 ),
2047 };
2048
2049 fields.is_some_and(|fields| {
2050 fields.iter().any(|vis| !self.r.is_accessible_from(*vis, self.parent_scope.module))
2051 })
2052 }
2053
2054 pub(crate) fn find_similarly_named_assoc_item(
2057 &mut self,
2058 ident: Symbol,
2059 kind: &AssocItemKind,
2060 ) -> Option<Symbol> {
2061 let (module, _) = self.current_trait_ref.as_ref()?;
2062 if ident == kw::Underscore {
2063 return None;
2065 }
2066
2067 let resolutions = self.r.resolutions(*module);
2068 let targets = resolutions
2069 .borrow()
2070 .iter()
2071 .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
2072 .filter(|(_, res)| match (kind, res) {
2073 (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
2074 (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
2075 (AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
2076 (AssocItemKind::Delegation(_), Res::Def(DefKind::AssocFn, _)) => true,
2077 _ => false,
2078 })
2079 .map(|(key, _)| key.ident.name)
2080 .collect::<Vec<_>>();
2081
2082 find_best_match_for_name(&targets, ident, None)
2083 }
2084
2085 fn lookup_assoc_candidate<FilterFn>(
2086 &mut self,
2087 ident: Ident,
2088 ns: Namespace,
2089 filter_fn: FilterFn,
2090 called: bool,
2091 ) -> Option<AssocSuggestion>
2092 where
2093 FilterFn: Fn(Res) -> bool,
2094 {
2095 fn extract_node_id(t: &Ty) -> Option<NodeId> {
2096 match t.kind {
2097 TyKind::Path(None, _) => Some(t.id),
2098 TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
2099 _ => None,
2103 }
2104 }
2105 if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
2107 if let Some(node_id) =
2108 self.diag_metadata.current_self_type.as_ref().and_then(extract_node_id)
2109 {
2110 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
2112 if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
2113 resolution.full_res()
2114 {
2115 if let Some(fields) = self.r.field_idents(did) {
2116 if let Some(field) = fields.iter().find(|id| ident.name == id.name) {
2117 return Some(AssocSuggestion::Field(field.span));
2118 }
2119 }
2120 }
2121 }
2122 }
2123 }
2124
2125 if let Some(items) = self.diag_metadata.current_trait_assoc_items {
2126 for assoc_item in items {
2127 if assoc_item.ident == ident {
2128 return Some(match &assoc_item.kind {
2129 ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
2130 ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
2131 AssocSuggestion::MethodWithSelf { called }
2132 }
2133 ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
2134 ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
2135 ast::AssocItemKind::Delegation(..)
2136 if self
2137 .r
2138 .delegation_fn_sigs
2139 .get(&self.r.local_def_id(assoc_item.id))
2140 .is_some_and(|sig| sig.has_self) =>
2141 {
2142 AssocSuggestion::MethodWithSelf { called }
2143 }
2144 ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
2145 ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
2146 continue;
2147 }
2148 });
2149 }
2150 }
2151 }
2152
2153 if let Some((module, _)) = self.current_trait_ref {
2155 if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
2156 ModuleOrUniformRoot::Module(module),
2157 ident,
2158 ns,
2159 &self.parent_scope,
2160 None,
2161 ) {
2162 let res = binding.res();
2163 if filter_fn(res) {
2164 match res {
2165 Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
2166 let has_self = match def_id.as_local() {
2167 Some(def_id) => self
2168 .r
2169 .delegation_fn_sigs
2170 .get(&def_id)
2171 .is_some_and(|sig| sig.has_self),
2172 None => self
2173 .r
2174 .tcx
2175 .fn_arg_names(def_id)
2176 .first()
2177 .is_some_and(|ident| ident.name == kw::SelfLower),
2178 };
2179 if has_self {
2180 return Some(AssocSuggestion::MethodWithSelf { called });
2181 } else {
2182 return Some(AssocSuggestion::AssocFn { called });
2183 }
2184 }
2185 Res::Def(DefKind::AssocConst, _) => {
2186 return Some(AssocSuggestion::AssocConst);
2187 }
2188 Res::Def(DefKind::AssocTy, _) => {
2189 return Some(AssocSuggestion::AssocType);
2190 }
2191 _ => {}
2192 }
2193 }
2194 }
2195 }
2196
2197 None
2198 }
2199
2200 fn lookup_typo_candidate(
2201 &mut self,
2202 path: &[Segment],
2203 following_seg: Option<&Segment>,
2204 ns: Namespace,
2205 filter_fn: &impl Fn(Res) -> bool,
2206 ) -> TypoCandidate {
2207 let mut names = Vec::new();
2208 if let [segment] = path {
2209 let mut ctxt = segment.ident.span.ctxt();
2210
2211 for rib in self.ribs[ns].iter().rev() {
2214 let rib_ctxt = if rib.kind.contains_params() {
2215 ctxt.normalize_to_macros_2_0()
2216 } else {
2217 ctxt.normalize_to_macro_rules()
2218 };
2219
2220 for (ident, &res) in &rib.bindings {
2222 if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
2223 names.push(TypoSuggestion::typo_from_ident(*ident, res));
2224 }
2225 }
2226
2227 if let RibKind::MacroDefinition(def) = rib.kind
2228 && def == self.r.macro_def(ctxt)
2229 {
2230 ctxt.remove_mark();
2233 continue;
2234 }
2235
2236 if let RibKind::Module(module) = rib.kind {
2238 self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
2240
2241 if let ModuleKind::Block = module.kind {
2242 } else {
2244 if !module.no_implicit_prelude {
2246 let extern_prelude = self.r.extern_prelude.clone();
2247 names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
2248 self.r
2249 .crate_loader(|c| c.maybe_process_path_extern(ident.name))
2250 .and_then(|crate_id| {
2251 let crate_mod =
2252 Res::Def(DefKind::Mod, crate_id.as_def_id());
2253
2254 filter_fn(crate_mod).then(|| {
2255 TypoSuggestion::typo_from_ident(*ident, crate_mod)
2256 })
2257 })
2258 }));
2259
2260 if let Some(prelude) = self.r.prelude {
2261 self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
2262 }
2263 }
2264 break;
2265 }
2266 }
2267 }
2268 if filter_fn(Res::PrimTy(PrimTy::Bool)) {
2270 names.extend(PrimTy::ALL.iter().map(|prim_ty| {
2271 TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
2272 }))
2273 }
2274 } else {
2275 let mod_path = &path[..path.len() - 1];
2277 if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
2278 self.resolve_path(mod_path, Some(TypeNS), None)
2279 {
2280 self.r.add_module_candidates(module, &mut names, &filter_fn, None);
2281 }
2282 }
2283
2284 if let Some(following_seg) = following_seg {
2286 names.retain(|suggestion| match suggestion.res {
2287 Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
2288 suggestion.candidate != following_seg.ident.name
2290 }
2291 Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
2292 || false,
2293 |module| {
2294 self.r
2295 .resolutions(module)
2296 .borrow()
2297 .iter()
2298 .any(|(key, _)| key.ident.name == following_seg.ident.name)
2299 },
2300 ),
2301 _ => true,
2302 });
2303 }
2304 let name = path[path.len() - 1].ident.name;
2305 names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
2307
2308 match find_best_match_for_name(
2309 &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
2310 name,
2311 None,
2312 ) {
2313 Some(found) => {
2314 let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found)
2315 else {
2316 return TypoCandidate::None;
2317 };
2318 if found == name {
2319 TypoCandidate::Shadowed(sugg.res, sugg.span)
2320 } else {
2321 TypoCandidate::Typo(sugg)
2322 }
2323 }
2324 _ => TypoCandidate::None,
2325 }
2326 }
2327
2328 fn likely_rust_type(path: &[Segment]) -> Option<Symbol> {
2331 let name = path[path.len() - 1].ident.as_str();
2332 Some(match name {
2334 "byte" => sym::u8, "short" => sym::i16,
2336 "Bool" => sym::bool,
2337 "Boolean" => sym::bool,
2338 "boolean" => sym::bool,
2339 "int" => sym::i32,
2340 "long" => sym::i64,
2341 "float" => sym::f32,
2342 "double" => sym::f64,
2343 _ => return None,
2344 })
2345 }
2346
2347 fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool {
2350 if ident_span.from_expansion() {
2351 return false;
2352 }
2353
2354 if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) = self.diag_metadata.in_assignment
2356 && let ast::ExprKind::Path(None, ref path) = lhs.kind
2357 && self.r.tcx.sess.source_map().is_line_before_span_empty(ident_span)
2358 {
2359 let (span, text) = match path.segments.first() {
2360 Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => {
2361 let name = name.strip_prefix('_').unwrap_or(name);
2363 (ident_span, format!("let {name}"))
2364 }
2365 _ => (ident_span.shrink_to_lo(), "let ".to_string()),
2366 };
2367
2368 err.span_suggestion_verbose(
2369 span,
2370 "you might have meant to introduce a new binding",
2371 text,
2372 Applicability::MaybeIncorrect,
2373 );
2374 return true;
2375 }
2376
2377 if err.code == Some(E0423)
2380 && let Some((let_span, None, Some(val_span))) = self.diag_metadata.current_let_binding
2381 && val_span.contains(ident_span)
2382 && val_span.lo() == ident_span.lo()
2383 {
2384 err.span_suggestion_verbose(
2385 let_span.shrink_to_hi().to(val_span.shrink_to_lo()),
2386 "you might have meant to use `:` for type annotation",
2387 ": ",
2388 Applicability::MaybeIncorrect,
2389 );
2390 return true;
2391 }
2392 false
2393 }
2394
2395 fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> {
2396 let mut result = None;
2397 let mut seen_modules = FxHashSet::default();
2398 let root_did = self.r.graph_root.def_id();
2399 let mut worklist = vec![(
2400 self.r.graph_root,
2401 ThinVec::new(),
2402 root_did.is_local() || !self.r.tcx.is_doc_hidden(root_did),
2403 )];
2404
2405 while let Some((in_module, path_segments, doc_visible)) = worklist.pop() {
2406 if result.is_some() {
2408 break;
2409 }
2410
2411 in_module.for_each_child(self.r, |r, ident, _, name_binding| {
2412 if result.is_some() || !name_binding.vis.is_visible_locally() {
2414 return;
2415 }
2416 if let Some(module) = name_binding.module() {
2417 let mut path_segments = path_segments.clone();
2419 path_segments.push(ast::PathSegment::from_ident(ident));
2420 let module_def_id = module.def_id();
2421 let doc_visible = doc_visible
2422 && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id));
2423 if module_def_id == def_id {
2424 let path =
2425 Path { span: name_binding.span, segments: path_segments, tokens: None };
2426 result = Some((
2427 module,
2428 ImportSuggestion {
2429 did: Some(def_id),
2430 descr: "module",
2431 path,
2432 accessible: true,
2433 doc_visible,
2434 note: None,
2435 via_import: false,
2436 },
2437 ));
2438 } else {
2439 if seen_modules.insert(module_def_id) {
2441 worklist.push((module, path_segments, doc_visible));
2442 }
2443 }
2444 }
2445 });
2446 }
2447
2448 result
2449 }
2450
2451 fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
2452 self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
2453 let mut variants = Vec::new();
2454 enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
2455 if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
2456 let mut segms = enum_import_suggestion.path.segments.clone();
2457 segms.push(ast::PathSegment::from_ident(ident));
2458 let path = Path { span: name_binding.span, segments: segms, tokens: None };
2459 variants.push((path, def_id, kind));
2460 }
2461 });
2462 variants
2463 })
2464 }
2465
2466 fn suggest_using_enum_variant(
2468 &mut self,
2469 err: &mut Diag<'_>,
2470 source: PathSource<'_>,
2471 def_id: DefId,
2472 span: Span,
2473 ) {
2474 let Some(variants) = self.collect_enum_ctors(def_id) else {
2475 err.note("you might have meant to use one of the enum's variants");
2476 return;
2477 };
2478
2479 let suggest_only_tuple_variants =
2480 matches!(source, PathSource::TupleStruct(..)) || source.is_call();
2481 if suggest_only_tuple_variants {
2482 let mut suggestable_variants = variants
2485 .iter()
2486 .filter(|(.., kind)| *kind == CtorKind::Fn)
2487 .map(|(variant, ..)| path_names_to_string(variant))
2488 .collect::<Vec<_>>();
2489 suggestable_variants.sort();
2490
2491 let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
2492
2493 let source_msg = if source.is_call() {
2494 "to construct"
2495 } else if matches!(source, PathSource::TupleStruct(..)) {
2496 "to match against"
2497 } else {
2498 unreachable!()
2499 };
2500
2501 if !suggestable_variants.is_empty() {
2502 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
2503 format!("try {source_msg} the enum's variant")
2504 } else {
2505 format!("try {source_msg} one of the enum's variants")
2506 };
2507
2508 err.span_suggestions(
2509 span,
2510 msg,
2511 suggestable_variants,
2512 Applicability::MaybeIncorrect,
2513 );
2514 }
2515
2516 if non_suggestable_variant_count == variants.len() {
2518 err.help(format!("the enum has no tuple variants {source_msg}"));
2519 }
2520
2521 if non_suggestable_variant_count == 1 {
2523 err.help(format!("you might have meant {source_msg} the enum's non-tuple variant"));
2524 } else if non_suggestable_variant_count >= 1 {
2525 err.help(format!(
2526 "you might have meant {source_msg} one of the enum's non-tuple variants"
2527 ));
2528 }
2529 } else {
2530 let needs_placeholder = |ctor_def_id: DefId, kind: CtorKind| {
2531 let def_id = self.r.tcx.parent(ctor_def_id);
2532 match kind {
2533 CtorKind::Const => false,
2534 CtorKind::Fn => {
2535 !self.r.field_idents(def_id).is_some_and(|field_ids| field_ids.is_empty())
2536 }
2537 }
2538 };
2539
2540 let mut suggestable_variants = variants
2541 .iter()
2542 .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
2543 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
2544 .map(|(variant, kind)| match kind {
2545 CtorKind::Const => variant,
2546 CtorKind::Fn => format!("({variant}())"),
2547 })
2548 .collect::<Vec<_>>();
2549 suggestable_variants.sort();
2550 let no_suggestable_variant = suggestable_variants.is_empty();
2551
2552 if !no_suggestable_variant {
2553 let msg = if suggestable_variants.len() == 1 {
2554 "you might have meant to use the following enum variant"
2555 } else {
2556 "you might have meant to use one of the following enum variants"
2557 };
2558
2559 err.span_suggestions(
2560 span,
2561 msg,
2562 suggestable_variants,
2563 Applicability::MaybeIncorrect,
2564 );
2565 }
2566
2567 let mut suggestable_variants_with_placeholders = variants
2568 .iter()
2569 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
2570 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
2571 .filter_map(|(variant, kind)| match kind {
2572 CtorKind::Fn => Some(format!("({variant}(/* fields */))")),
2573 _ => None,
2574 })
2575 .collect::<Vec<_>>();
2576 suggestable_variants_with_placeholders.sort();
2577
2578 if !suggestable_variants_with_placeholders.is_empty() {
2579 let msg =
2580 match (no_suggestable_variant, suggestable_variants_with_placeholders.len()) {
2581 (true, 1) => "the following enum variant is available",
2582 (true, _) => "the following enum variants are available",
2583 (false, 1) => "alternatively, the following enum variant is available",
2584 (false, _) => {
2585 "alternatively, the following enum variants are also available"
2586 }
2587 };
2588
2589 err.span_suggestions(
2590 span,
2591 msg,
2592 suggestable_variants_with_placeholders,
2593 Applicability::HasPlaceholders,
2594 );
2595 }
2596 };
2597
2598 if def_id.is_local() {
2599 err.span_note(self.r.def_span(def_id), "the enum is defined here");
2600 }
2601 }
2602
2603 pub(crate) fn suggest_adding_generic_parameter(
2604 &self,
2605 path: &[Segment],
2606 source: PathSource<'_>,
2607 ) -> Option<(Span, &'static str, String, Applicability)> {
2608 let (ident, span) = match path {
2609 [segment]
2610 if !segment.has_generic_args
2611 && segment.ident.name != kw::SelfUpper
2612 && segment.ident.name != kw::Dyn =>
2613 {
2614 (segment.ident.to_string(), segment.ident.span)
2615 }
2616 _ => return None,
2617 };
2618 let mut iter = ident.chars().map(|c| c.is_uppercase());
2619 let single_uppercase_char =
2620 matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
2621 if !self.diag_metadata.currently_processing_generic_args && !single_uppercase_char {
2622 return None;
2623 }
2624 match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) {
2625 (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
2626 }
2628 (
2629 Some(Item {
2630 kind:
2631 kind @ ItemKind::Fn(..)
2632 | kind @ ItemKind::Enum(..)
2633 | kind @ ItemKind::Struct(..)
2634 | kind @ ItemKind::Union(..),
2635 ..
2636 }),
2637 true, _
2638 )
2639 | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
2641 | (Some(Item { kind, .. }), false, _) => {
2642 if let Some(generics) = kind.generics() {
2643 if span.overlaps(generics.span) {
2644 return None;
2653 }
2654
2655 let (msg, sugg) = match source {
2656 PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => {
2657 ("you might be missing a type parameter", ident)
2658 }
2659 PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => (
2660 "you might be missing a const parameter",
2661 format!("const {ident}: /* Type */"),
2662 ),
2663 _ => return None,
2664 };
2665 let (span, sugg) = if let [.., param] = &generics.params[..] {
2666 let span = if let [.., bound] = ¶m.bounds[..] {
2667 bound.span()
2668 } else if let GenericParam {
2669 kind: GenericParamKind::Const { ty, kw_span: _, default }, ..
2670 } = param {
2671 default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
2672 } else {
2673 param.ident.span
2674 };
2675 (span, format!(", {sugg}"))
2676 } else {
2677 (generics.span, format!("<{sugg}>"))
2678 };
2679 if span.can_be_used_for_suggestions() {
2681 return Some((
2682 span.shrink_to_hi(),
2683 msg,
2684 sugg,
2685 Applicability::MaybeIncorrect,
2686 ));
2687 }
2688 }
2689 }
2690 _ => {}
2691 }
2692 None
2693 }
2694
2695 pub(crate) fn suggestion_for_label_in_rib(
2698 &self,
2699 rib_index: usize,
2700 label: Ident,
2701 ) -> Option<LabelSuggestion> {
2702 let within_scope = self.is_label_valid_from_rib(rib_index);
2704
2705 let rib = &self.label_ribs[rib_index];
2706 let names = rib
2707 .bindings
2708 .iter()
2709 .filter(|(id, _)| id.span.eq_ctxt(label.span))
2710 .map(|(id, _)| id.name)
2711 .collect::<Vec<Symbol>>();
2712
2713 find_best_match_for_name(&names, label.name, None).map(|symbol| {
2714 let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
2718 (*ident, within_scope)
2719 })
2720 }
2721
2722 pub(crate) fn maybe_report_lifetime_uses(
2723 &mut self,
2724 generics_span: Span,
2725 params: &[ast::GenericParam],
2726 ) {
2727 for (param_index, param) in params.iter().enumerate() {
2728 let GenericParamKind::Lifetime = param.kind else { continue };
2729
2730 let def_id = self.r.local_def_id(param.id);
2731
2732 let use_set = self.lifetime_uses.remove(&def_id);
2733 debug!(
2734 "Use set for {:?}({:?} at {:?}) is {:?}",
2735 def_id, param.ident, param.ident.span, use_set
2736 );
2737
2738 let deletion_span = || {
2739 if params.len() == 1 {
2740 Some(generics_span)
2742 } else if param_index == 0 {
2743 match (
2746 param.span().find_ancestor_inside(generics_span),
2747 params[param_index + 1].span().find_ancestor_inside(generics_span),
2748 ) {
2749 (Some(param_span), Some(next_param_span)) => {
2750 Some(param_span.to(next_param_span.shrink_to_lo()))
2751 }
2752 _ => None,
2753 }
2754 } else {
2755 match (
2758 param.span().find_ancestor_inside(generics_span),
2759 params[param_index - 1].span().find_ancestor_inside(generics_span),
2760 ) {
2761 (Some(param_span), Some(prev_param_span)) => {
2762 Some(prev_param_span.shrink_to_hi().to(param_span))
2763 }
2764 _ => None,
2765 }
2766 }
2767 };
2768 match use_set {
2769 Some(LifetimeUseSet::Many) => {}
2770 Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
2771 debug!(?param.ident, ?param.ident.span, ?use_span);
2772
2773 let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
2774 let deletion_span =
2775 if param.bounds.is_empty() { deletion_span() } else { None };
2776
2777 self.r.lint_buffer.buffer_lint(
2778 lint::builtin::SINGLE_USE_LIFETIMES,
2779 param.id,
2780 param.ident.span,
2781 lint::BuiltinLintDiag::SingleUseLifetime {
2782 param_span: param.ident.span,
2783 use_span: Some((use_span, elidable)),
2784 deletion_span,
2785 ident: param.ident,
2786 },
2787 );
2788 }
2789 None => {
2790 debug!(?param.ident, ?param.ident.span);
2791 let deletion_span = deletion_span();
2792
2793 if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
2795 self.r.lint_buffer.buffer_lint(
2796 lint::builtin::UNUSED_LIFETIMES,
2797 param.id,
2798 param.ident.span,
2799 lint::BuiltinLintDiag::SingleUseLifetime {
2800 param_span: param.ident.span,
2801 use_span: None,
2802 deletion_span,
2803 ident: param.ident,
2804 },
2805 );
2806 }
2807 }
2808 }
2809 }
2810 }
2811
2812 pub(crate) fn emit_undeclared_lifetime_error(
2813 &self,
2814 lifetime_ref: &ast::Lifetime,
2815 outer_lifetime_ref: Option<Ident>,
2816 ) {
2817 debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
2818 let mut err = if let Some(outer) = outer_lifetime_ref {
2819 struct_span_code_err!(
2820 self.r.dcx(),
2821 lifetime_ref.ident.span,
2822 E0401,
2823 "can't use generic parameters from outer item",
2824 )
2825 .with_span_label(lifetime_ref.ident.span, "use of generic parameter from outer item")
2826 .with_span_label(outer.span, "lifetime parameter from outer item")
2827 } else {
2828 struct_span_code_err!(
2829 self.r.dcx(),
2830 lifetime_ref.ident.span,
2831 E0261,
2832 "use of undeclared lifetime name `{}`",
2833 lifetime_ref.ident
2834 )
2835 .with_span_label(lifetime_ref.ident.span, "undeclared lifetime")
2836 };
2837 self.suggest_introducing_lifetime(
2838 &mut err,
2839 Some(lifetime_ref.ident.name.as_str()),
2840 |err, _, span, message, suggestion, span_suggs| {
2841 err.multipart_suggestion_with_style(
2842 message,
2843 std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
2844 Applicability::MaybeIncorrect,
2845 if span_suggs.is_empty() {
2846 SuggestionStyle::ShowCode
2847 } else {
2848 SuggestionStyle::ShowAlways
2849 },
2850 );
2851 true
2852 },
2853 );
2854 err.emit();
2855 }
2856
2857 fn suggest_introducing_lifetime(
2858 &self,
2859 err: &mut Diag<'_>,
2860 name: Option<&str>,
2861 suggest: impl Fn(
2862 &mut Diag<'_>,
2863 bool,
2864 Span,
2865 Cow<'static, str>,
2866 String,
2867 Vec<(Span, String)>,
2868 ) -> bool,
2869 ) {
2870 let mut suggest_note = true;
2871 for rib in self.lifetime_ribs.iter().rev() {
2872 let mut should_continue = true;
2873 match rib.kind {
2874 LifetimeRibKind::Generics { binder, span, kind } => {
2875 if let LifetimeBinderKind::ConstItem = kind
2878 && !self.r.tcx().features().generic_const_items()
2879 {
2880 continue;
2881 }
2882
2883 if !span.can_be_used_for_suggestions()
2884 && suggest_note
2885 && let Some(name) = name
2886 {
2887 suggest_note = false; err.span_label(
2889 span,
2890 format!(
2891 "lifetime `{name}` is missing in item created through this procedural macro",
2892 ),
2893 );
2894 continue;
2895 }
2896
2897 let higher_ranked = matches!(
2898 kind,
2899 LifetimeBinderKind::BareFnType
2900 | LifetimeBinderKind::PolyTrait
2901 | LifetimeBinderKind::WhereBound
2902 );
2903
2904 let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
2905 let (span, sugg) = if span.is_empty() {
2906 let mut binder_idents: FxIndexSet<Ident> = Default::default();
2907 binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
2908
2909 if let LifetimeBinderKind::WhereBound = kind
2916 && let Some(predicate) = self.diag_metadata.current_where_predicate
2917 && let ast::WherePredicateKind::BoundPredicate(
2918 ast::WhereBoundPredicate { bounded_ty, bounds, .. },
2919 ) = &predicate.kind
2920 && bounded_ty.id == binder
2921 {
2922 for bound in bounds {
2923 if let ast::GenericBound::Trait(poly_trait_ref) = bound
2924 && let span = poly_trait_ref
2925 .span
2926 .with_hi(poly_trait_ref.trait_ref.path.span.lo())
2927 && !span.is_empty()
2928 {
2929 rm_inner_binders.insert(span);
2930 poly_trait_ref.bound_generic_params.iter().for_each(|v| {
2931 binder_idents.insert(v.ident);
2932 });
2933 }
2934 }
2935 }
2936
2937 let binders_sugg = binder_idents.into_iter().enumerate().fold(
2938 "".to_string(),
2939 |mut binders, (i, x)| {
2940 if i != 0 {
2941 binders += ", ";
2942 }
2943 binders += x.as_str();
2944 binders
2945 },
2946 );
2947 let sugg = format!(
2948 "{}<{}>{}",
2949 if higher_ranked { "for" } else { "" },
2950 binders_sugg,
2951 if higher_ranked { " " } else { "" },
2952 );
2953 (span, sugg)
2954 } else {
2955 let span = self
2956 .r
2957 .tcx
2958 .sess
2959 .source_map()
2960 .span_through_char(span, '<')
2961 .shrink_to_hi();
2962 let sugg = format!("{}, ", name.unwrap_or("'a"));
2963 (span, sugg)
2964 };
2965
2966 if higher_ranked {
2967 let message = Cow::from(format!(
2968 "consider making the {} lifetime-generic with a new `{}` lifetime",
2969 kind.descr(),
2970 name.unwrap_or("'a"),
2971 ));
2972 should_continue = suggest(
2973 err,
2974 true,
2975 span,
2976 message,
2977 sugg,
2978 if !rm_inner_binders.is_empty() {
2979 rm_inner_binders
2980 .into_iter()
2981 .map(|v| (v, "".to_string()))
2982 .collect::<Vec<_>>()
2983 } else {
2984 vec![]
2985 },
2986 );
2987 err.note_once(
2988 "for more information on higher-ranked polymorphism, visit \
2989 https://doc.rust-lang.org/nomicon/hrtb.html",
2990 );
2991 } else if let Some(name) = name {
2992 let message =
2993 Cow::from(format!("consider introducing lifetime `{name}` here"));
2994 should_continue = suggest(err, false, span, message, sugg, vec![]);
2995 } else {
2996 let message = Cow::from("consider introducing a named lifetime parameter");
2997 should_continue = suggest(err, false, span, message, sugg, vec![]);
2998 }
2999 }
3000 LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
3001 _ => {}
3002 }
3003 if !should_continue {
3004 break;
3005 }
3006 }
3007 }
3008
3009 pub(crate) fn emit_non_static_lt_in_const_param_ty_error(&self, lifetime_ref: &ast::Lifetime) {
3010 self.r
3011 .dcx()
3012 .create_err(errors::ParamInTyOfConstParam {
3013 span: lifetime_ref.ident.span,
3014 name: lifetime_ref.ident.name,
3015 param_kind: Some(errors::ParamKindInTyOfConstParam::Lifetime),
3016 })
3017 .emit();
3018 }
3019
3020 pub(crate) fn emit_forbidden_non_static_lifetime_error(
3024 &self,
3025 cause: NoConstantGenericsReason,
3026 lifetime_ref: &ast::Lifetime,
3027 ) {
3028 match cause {
3029 NoConstantGenericsReason::IsEnumDiscriminant => {
3030 self.r
3031 .dcx()
3032 .create_err(errors::ParamInEnumDiscriminant {
3033 span: lifetime_ref.ident.span,
3034 name: lifetime_ref.ident.name,
3035 param_kind: errors::ParamKindInEnumDiscriminant::Lifetime,
3036 })
3037 .emit();
3038 }
3039 NoConstantGenericsReason::NonTrivialConstArg => {
3040 assert!(!self.r.tcx.features().generic_const_exprs());
3041 self.r
3042 .dcx()
3043 .create_err(errors::ParamInNonTrivialAnonConst {
3044 span: lifetime_ref.ident.span,
3045 name: lifetime_ref.ident.name,
3046 param_kind: errors::ParamKindInNonTrivialAnonConst::Lifetime,
3047 help: self
3048 .r
3049 .tcx
3050 .sess
3051 .is_nightly_build()
3052 .then_some(errors::ParamInNonTrivialAnonConstHelp),
3053 })
3054 .emit();
3055 }
3056 }
3057 }
3058
3059 pub(crate) fn report_missing_lifetime_specifiers(
3060 &mut self,
3061 lifetime_refs: Vec<MissingLifetime>,
3062 function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
3063 ) -> ErrorGuaranteed {
3064 let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum();
3065 let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
3066
3067 let mut err = struct_span_code_err!(
3068 self.r.dcx(),
3069 spans,
3070 E0106,
3071 "missing lifetime specifier{}",
3072 pluralize!(num_lifetimes)
3073 );
3074 self.add_missing_lifetime_specifiers_label(
3075 &mut err,
3076 lifetime_refs,
3077 function_param_lifetimes,
3078 );
3079 err.emit()
3080 }
3081
3082 fn add_missing_lifetime_specifiers_label(
3083 &mut self,
3084 err: &mut Diag<'_>,
3085 lifetime_refs: Vec<MissingLifetime>,
3086 function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
3087 ) {
3088 for < in &lifetime_refs {
3089 err.span_label(
3090 lt.span,
3091 format!(
3092 "expected {} lifetime parameter{}",
3093 if lt.count == 1 { "named".to_string() } else { lt.count.to_string() },
3094 pluralize!(lt.count),
3095 ),
3096 );
3097 }
3098
3099 let mut in_scope_lifetimes: Vec<_> = self
3100 .lifetime_ribs
3101 .iter()
3102 .rev()
3103 .take_while(|rib| {
3104 !matches!(rib.kind, LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy)
3105 })
3106 .flat_map(|rib| rib.bindings.iter())
3107 .map(|(&ident, &res)| (ident, res))
3108 .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
3109 .collect();
3110 debug!(?in_scope_lifetimes);
3111
3112 let mut maybe_static = false;
3113 debug!(?function_param_lifetimes);
3114 if let Some((param_lifetimes, params)) = &function_param_lifetimes {
3115 let elided_len = param_lifetimes.len();
3116 let num_params = params.len();
3117
3118 let mut m = String::new();
3119
3120 for (i, info) in params.iter().enumerate() {
3121 let ElisionFnParameter { ident, index, lifetime_count, span } = *info;
3122 debug_assert_ne!(lifetime_count, 0);
3123
3124 err.span_label(span, "");
3125
3126 if i != 0 {
3127 if i + 1 < num_params {
3128 m.push_str(", ");
3129 } else if num_params == 2 {
3130 m.push_str(" or ");
3131 } else {
3132 m.push_str(", or ");
3133 }
3134 }
3135
3136 let help_name = if let Some(ident) = ident {
3137 format!("`{ident}`")
3138 } else {
3139 format!("argument {}", index + 1)
3140 };
3141
3142 if lifetime_count == 1 {
3143 m.push_str(&help_name[..])
3144 } else {
3145 m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..])
3146 }
3147 }
3148
3149 if num_params == 0 {
3150 err.help(
3151 "this function's return type contains a borrowed value, but there is no value \
3152 for it to be borrowed from",
3153 );
3154 if in_scope_lifetimes.is_empty() {
3155 maybe_static = true;
3156 in_scope_lifetimes = vec![(
3157 Ident::with_dummy_span(kw::StaticLifetime),
3158 (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
3159 )];
3160 }
3161 } else if elided_len == 0 {
3162 err.help(
3163 "this function's return type contains a borrowed value with an elided \
3164 lifetime, but the lifetime cannot be derived from the arguments",
3165 );
3166 if in_scope_lifetimes.is_empty() {
3167 maybe_static = true;
3168 in_scope_lifetimes = vec![(
3169 Ident::with_dummy_span(kw::StaticLifetime),
3170 (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
3171 )];
3172 }
3173 } else if num_params == 1 {
3174 err.help(format!(
3175 "this function's return type contains a borrowed value, but the signature does \
3176 not say which {m} it is borrowed from",
3177 ));
3178 } else {
3179 err.help(format!(
3180 "this function's return type contains a borrowed value, but the signature does \
3181 not say whether it is borrowed from {m}",
3182 ));
3183 }
3184 }
3185
3186 #[allow(rustc::symbol_intern_string_literal)]
3187 let existing_name = match &in_scope_lifetimes[..] {
3188 [] => Symbol::intern("'a"),
3189 [(existing, _)] => existing.name,
3190 _ => Symbol::intern("'lifetime"),
3191 };
3192
3193 let mut spans_suggs: Vec<_> = Vec::new();
3194 let build_sugg = |lt: MissingLifetime| match lt.kind {
3195 MissingLifetimeKind::Underscore => {
3196 debug_assert_eq!(lt.count, 1);
3197 (lt.span, existing_name.to_string())
3198 }
3199 MissingLifetimeKind::Ampersand => {
3200 debug_assert_eq!(lt.count, 1);
3201 (lt.span.shrink_to_hi(), format!("{existing_name} "))
3202 }
3203 MissingLifetimeKind::Comma => {
3204 let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
3205 .take(lt.count)
3206 .flatten()
3207 .collect();
3208 (lt.span.shrink_to_hi(), sugg)
3209 }
3210 MissingLifetimeKind::Brackets => {
3211 let sugg: String = std::iter::once("<")
3212 .chain(
3213 std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "),
3214 )
3215 .chain([">"])
3216 .collect();
3217 (lt.span.shrink_to_hi(), sugg)
3218 }
3219 };
3220 for < in &lifetime_refs {
3221 spans_suggs.push(build_sugg(lt));
3222 }
3223 debug!(?spans_suggs);
3224 match in_scope_lifetimes.len() {
3225 0 => {
3226 if let Some((param_lifetimes, _)) = function_param_lifetimes {
3227 for lt in param_lifetimes {
3228 spans_suggs.push(build_sugg(lt))
3229 }
3230 }
3231 self.suggest_introducing_lifetime(
3232 err,
3233 None,
3234 |err, higher_ranked, span, message, intro_sugg, _| {
3235 err.multipart_suggestion_verbose(
3236 message,
3237 std::iter::once((span, intro_sugg))
3238 .chain(spans_suggs.clone())
3239 .collect(),
3240 Applicability::MaybeIncorrect,
3241 );
3242 higher_ranked
3243 },
3244 );
3245 }
3246 1 => {
3247 let post = if maybe_static {
3248 let owned = if let [lt] = &lifetime_refs[..]
3249 && lt.kind != MissingLifetimeKind::Ampersand
3250 {
3251 ", or if you will only have owned values"
3252 } else {
3253 ""
3254 };
3255 format!(
3256 ", but this is uncommon unless you're returning a borrowed value from a \
3257 `const` or a `static`{owned}",
3258 )
3259 } else {
3260 String::new()
3261 };
3262 err.multipart_suggestion_verbose(
3263 format!("consider using the `{existing_name}` lifetime{post}"),
3264 spans_suggs,
3265 Applicability::MaybeIncorrect,
3266 );
3267 if maybe_static {
3268 if let [lt] = &lifetime_refs[..]
3274 && (lt.kind == MissingLifetimeKind::Ampersand
3275 || lt.kind == MissingLifetimeKind::Underscore)
3276 {
3277 let pre = if lt.kind == MissingLifetimeKind::Ampersand
3278 && let Some((kind, _span)) = self.diag_metadata.current_function
3279 && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3280 && !sig.decl.inputs.is_empty()
3281 && let sugg = sig
3282 .decl
3283 .inputs
3284 .iter()
3285 .filter_map(|param| {
3286 if param.ty.span.contains(lt.span) {
3287 None
3290 } else if let TyKind::CVarArgs = param.ty.kind {
3291 None
3293 } else if let TyKind::ImplTrait(..) = ¶m.ty.kind {
3294 None
3296 } else {
3297 Some((param.ty.span.shrink_to_lo(), "&".to_string()))
3298 }
3299 })
3300 .collect::<Vec<_>>()
3301 && !sugg.is_empty()
3302 {
3303 let (the, s) = if sig.decl.inputs.len() == 1 {
3304 ("the", "")
3305 } else {
3306 ("one of the", "s")
3307 };
3308 err.multipart_suggestion_verbose(
3309 format!(
3310 "instead, you are more likely to want to change {the} \
3311 argument{s} to be borrowed...",
3312 ),
3313 sugg,
3314 Applicability::MaybeIncorrect,
3315 );
3316 "...or alternatively, you might want"
3317 } else if (lt.kind == MissingLifetimeKind::Ampersand
3318 || lt.kind == MissingLifetimeKind::Underscore)
3319 && let Some((kind, _span)) = self.diag_metadata.current_function
3320 && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3321 && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
3322 && !sig.decl.inputs.is_empty()
3323 && let arg_refs = sig
3324 .decl
3325 .inputs
3326 .iter()
3327 .filter_map(|param| match ¶m.ty.kind {
3328 TyKind::ImplTrait(_, bounds) => Some(bounds),
3329 _ => None,
3330 })
3331 .flat_map(|bounds| bounds.into_iter())
3332 .collect::<Vec<_>>()
3333 && !arg_refs.is_empty()
3334 {
3335 let mut lt_finder =
3341 LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
3342 for bound in arg_refs {
3343 if let ast::GenericBound::Trait(trait_ref) = bound {
3344 lt_finder.visit_trait_ref(&trait_ref.trait_ref);
3345 }
3346 }
3347 lt_finder.visit_ty(ret_ty);
3348 let spans_suggs: Vec<_> = lt_finder
3349 .seen
3350 .iter()
3351 .filter_map(|ty| match &ty.kind {
3352 TyKind::Ref(_, mut_ty) => {
3353 let span = ty.span.with_hi(mut_ty.ty.span.lo());
3354 Some((span, "&'a ".to_string()))
3355 }
3356 _ => None,
3357 })
3358 .collect();
3359 self.suggest_introducing_lifetime(
3360 err,
3361 None,
3362 |err, higher_ranked, span, message, intro_sugg, _| {
3363 err.multipart_suggestion_verbose(
3364 message,
3365 std::iter::once((span, intro_sugg))
3366 .chain(spans_suggs.clone())
3367 .collect(),
3368 Applicability::MaybeIncorrect,
3369 );
3370 higher_ranked
3371 },
3372 );
3373 "alternatively, you might want"
3374 } else {
3375 "instead, you are more likely to want"
3376 };
3377 let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
3378 let mut sugg = vec![(lt.span, String::new())];
3379 if let Some((kind, _span)) = self.diag_metadata.current_function
3380 && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3381 && let ast::FnRetTy::Ty(ty) = &sig.decl.output
3382 {
3383 let mut lt_finder =
3384 LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
3385 lt_finder.visit_ty(&ty);
3386
3387 if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
3388 <_finder.seen[..]
3389 {
3390 sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
3396 owned_sugg = true;
3397 }
3398 if let Some(ty) = lt_finder.found {
3399 if let TyKind::Path(None, path) = &ty.kind {
3400 let path: Vec<_> = Segment::from_path(path);
3402 match self.resolve_path(&path, Some(TypeNS), None) {
3403 PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
3404 match module.res() {
3405 Some(Res::PrimTy(PrimTy::Str)) => {
3406 sugg = vec![(
3408 lt.span.with_hi(ty.span.hi()),
3409 "String".to_string(),
3410 )];
3411 }
3412 Some(Res::PrimTy(..)) => {}
3413 Some(Res::Def(
3414 DefKind::Struct
3415 | DefKind::Union
3416 | DefKind::Enum
3417 | DefKind::ForeignTy
3418 | DefKind::AssocTy
3419 | DefKind::OpaqueTy
3420 | DefKind::TyParam,
3421 _,
3422 )) => {}
3423 _ => {
3424 owned_sugg = false;
3426 }
3427 }
3428 }
3429 PathResult::NonModule(res) => {
3430 match res.base_res() {
3431 Res::PrimTy(PrimTy::Str) => {
3432 sugg = vec![(
3434 lt.span.with_hi(ty.span.hi()),
3435 "String".to_string(),
3436 )];
3437 }
3438 Res::PrimTy(..) => {}
3439 Res::Def(
3440 DefKind::Struct
3441 | DefKind::Union
3442 | DefKind::Enum
3443 | DefKind::ForeignTy
3444 | DefKind::AssocTy
3445 | DefKind::OpaqueTy
3446 | DefKind::TyParam,
3447 _,
3448 ) => {}
3449 _ => {
3450 owned_sugg = false;
3452 }
3453 }
3454 }
3455 _ => {
3456 owned_sugg = false;
3458 }
3459 }
3460 }
3461 if let TyKind::Slice(inner_ty) = &ty.kind {
3462 sugg = vec![
3464 (lt.span.with_hi(inner_ty.span.lo()), "Vec<".to_string()),
3465 (ty.span.with_lo(inner_ty.span.hi()), ">".to_string()),
3466 ];
3467 }
3468 }
3469 }
3470 if owned_sugg {
3471 err.multipart_suggestion_verbose(
3472 format!("{pre} to return an owned value"),
3473 sugg,
3474 Applicability::MaybeIncorrect,
3475 );
3476 }
3477 }
3478 }
3479
3480 let (_, (_, res)) = in_scope_lifetimes[0];
3482 for < in &lifetime_refs {
3483 self.r.lifetimes_res_map.insert(lt.id, res);
3484 }
3485 }
3486 _ => {
3487 let lifetime_spans: Vec<_> =
3488 in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect();
3489 err.span_note(lifetime_spans, "these named lifetimes are available to use");
3490
3491 if spans_suggs.len() > 0 {
3492 err.multipart_suggestion_verbose(
3495 "consider using one of the available lifetimes here",
3496 spans_suggs,
3497 Applicability::HasPlaceholders,
3498 );
3499 }
3500 }
3501 }
3502 }
3503}
3504
3505fn mk_where_bound_predicate(
3506 path: &Path,
3507 poly_trait_ref: &ast::PolyTraitRef,
3508 ty: &Ty,
3509) -> Option<ast::WhereBoundPredicate> {
3510 let modified_segments = {
3511 let mut segments = path.segments.clone();
3512 let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
3513 return None;
3514 };
3515 let mut segments = ThinVec::from(preceding);
3516
3517 let added_constraint = ast::AngleBracketedArg::Constraint(ast::AssocItemConstraint {
3518 id: DUMMY_NODE_ID,
3519 ident: last.ident,
3520 gen_args: None,
3521 kind: ast::AssocItemConstraintKind::Equality {
3522 term: ast::Term::Ty(ast::ptr::P(ast::Ty {
3523 kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()),
3524 id: DUMMY_NODE_ID,
3525 span: DUMMY_SP,
3526 tokens: None,
3527 })),
3528 },
3529 span: DUMMY_SP,
3530 });
3531
3532 match second_last.args.as_deref_mut() {
3533 Some(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args, .. })) => {
3534 args.push(added_constraint);
3535 }
3536 Some(_) => return None,
3537 None => {
3538 second_last.args =
3539 Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs {
3540 args: ThinVec::from([added_constraint]),
3541 span: DUMMY_SP,
3542 })));
3543 }
3544 }
3545
3546 segments.push(second_last.clone());
3547 segments
3548 };
3549
3550 let new_where_bound_predicate = ast::WhereBoundPredicate {
3551 bound_generic_params: ThinVec::new(),
3552 bounded_ty: ast::ptr::P(ty.clone()),
3553 bounds: vec![ast::GenericBound::Trait(ast::PolyTraitRef {
3554 bound_generic_params: ThinVec::new(),
3555 modifiers: ast::TraitBoundModifiers::NONE,
3556 trait_ref: ast::TraitRef {
3557 path: ast::Path { segments: modified_segments, span: DUMMY_SP, tokens: None },
3558 ref_id: DUMMY_NODE_ID,
3559 },
3560 span: DUMMY_SP,
3561 })],
3562 };
3563
3564 Some(new_where_bound_predicate)
3565}
3566
3567pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
3569 struct_span_code_err!(
3570 sess.dcx(),
3571 shadower.span,
3572 E0496,
3573 "lifetime name `{}` shadows a lifetime name that is already in scope",
3574 orig.name,
3575 )
3576 .with_span_label(orig.span, "first declared here")
3577 .with_span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name))
3578 .emit();
3579}
3580
3581struct LifetimeFinder<'ast> {
3582 lifetime: Span,
3583 found: Option<&'ast Ty>,
3584 seen: Vec<&'ast Ty>,
3585}
3586
3587impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
3588 fn visit_ty(&mut self, t: &'ast Ty) {
3589 if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind {
3590 self.seen.push(t);
3591 if t.span.lo() == self.lifetime.lo() {
3592 self.found = Some(&mut_ty.ty);
3593 }
3594 }
3595 walk_ty(self, t)
3596 }
3597}
3598
3599pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
3602 let name = shadower.name;
3603 let shadower = shadower.span;
3604 sess.dcx()
3605 .struct_span_warn(
3606 shadower,
3607 format!("label name `{name}` shadows a label name that is already in scope"),
3608 )
3609 .with_span_label(orig, "first declared here")
3610 .with_span_label(shadower, format!("label `{name}` already in scope"))
3611 .emit();
3612}