]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_resolve/src/late/diagnostics.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / compiler / rustc_resolve / src / late / diagnostics.rs
CommitLineData
f035d41b 1use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
74b04a01 2use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
29967ef6 3use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
dfeec247
XL
4use crate::path_names_to_string;
5use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
6use crate::{PathResult, PathSource, Segment};
416331ca 7
3dfed10e 8use rustc_ast::visit::FnKind;
17df50a5
XL
9use rustc_ast::{
10 self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty,
11 TyKind,
12};
29967ef6 13use rustc_ast_pretty::pprust::path_segment_to_string;
dfeec247 14use rustc_data_structures::fx::FxHashSet;
17df50a5 15use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, SuggestionStyle};
74b04a01 16use rustc_hir as hir;
dfeec247 17use rustc_hir::def::Namespace::{self, *};
29967ef6 18use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
3dfed10e 19use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
dfeec247 20use rustc_hir::PrimTy;
1b1a35ee 21use rustc_session::parse::feature_err;
6a06907d 22use rustc_span::edition::Edition;
dfeec247 23use rustc_span::hygiene::MacroKind;
fc512014 24use rustc_span::lev_distance::find_best_match_for_name;
3dfed10e 25use rustc_span::symbol::{kw, sym, Ident, Symbol};
29967ef6 26use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
416331ca 27
cdc7bbd5
XL
28use std::iter;
29
3dfed10e 30use tracing::debug;
60c5eb7d 31
416331ca
XL
32type Res = def::Res<ast::NodeId>;
33
34/// A field or associated item from self type suggested in case of resolution failure.
35enum AssocSuggestion {
36 Field,
37 MethodWithSelf,
29967ef6
XL
38 AssocFn,
39 AssocType,
40 AssocConst,
41}
42
43impl AssocSuggestion {
44 fn action(&self) -> &'static str {
45 match self {
46 AssocSuggestion::Field => "use the available field",
47 AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path",
48 AssocSuggestion::AssocFn => "call the associated function",
49 AssocSuggestion::AssocConst => "use the associated `const`",
50 AssocSuggestion::AssocType => "use the associated type",
51 }
52 }
416331ca
XL
53}
54
74b04a01
XL
55crate enum MissingLifetimeSpot<'tcx> {
56 Generics(&'tcx hir::Generics<'tcx>),
57 HigherRanked { span: Span, span_type: ForLifetimeSpanType },
3dfed10e 58 Static,
74b04a01
XL
59}
60
61crate enum ForLifetimeSpanType {
62 BoundEmpty,
63 BoundTail,
64 TypeEmpty,
65 TypeTail,
66}
67
68impl ForLifetimeSpanType {
69 crate fn descr(&self) -> &'static str {
70 match self {
71 Self::BoundEmpty | Self::BoundTail => "bound",
72 Self::TypeEmpty | Self::TypeTail => "type",
73 }
74 }
75
76 crate fn suggestion(&self, sugg: &str) -> String {
77 match self {
78 Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
79 Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
80 }
81 }
82}
83
84impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
85 fn into(self) -> MissingLifetimeSpot<'tcx> {
86 MissingLifetimeSpot::Generics(self)
87 }
88}
89
416331ca
XL
90fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
91 namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
92}
93
94fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
95 namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
96}
97
98/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
99fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
100 let variant_path = &suggestion.path;
101 let variant_path_string = path_names_to_string(variant_path);
102
103 let path_len = suggestion.path.segments.len();
104 let enum_path = ast::Path {
105 span: suggestion.path.span,
106 segments: suggestion.path.segments[0..path_len - 1].to_vec(),
1b1a35ee 107 tokens: None,
416331ca
XL
108 };
109 let enum_path_string = path_names_to_string(&enum_path);
110
111 (variant_path_string, enum_path_string)
112}
113
1b1a35ee 114impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
3dfed10e
XL
115 fn def_span(&self, def_id: DefId) -> Option<Span> {
116 match def_id.krate {
117 LOCAL_CRATE => self.r.opt_span(def_id),
118 _ => Some(
119 self.r
120 .session
121 .source_map()
122 .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
123 ),
124 }
125 }
126
416331ca
XL
127 /// Handles error reporting for `smart_resolve_path_fragment` function.
128 /// Creates base error and amends it with one short label and possibly some longer helps/notes.
129 pub(crate) fn smart_resolve_report_errors(
130 &mut self,
131 path: &[Segment],
132 span: Span,
133 source: PathSource<'_>,
134 res: Option<Res>,
135 ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
136 let ident_span = path.last().map_or(span, |ident| ident.ident.span);
137 let ns = source.namespace();
138 let is_expected = &|res| source.is_expected(res);
f035d41b 139 let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
416331ca
XL
140
141 // Make the base error.
6a06907d 142 let mut expected = source.descr_expected();
416331ca
XL
143 let path_str = Segment::names_to_string(path);
144 let item_str = path.last().unwrap().ident;
e74abb32 145 let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res {
dfeec247
XL
146 (
147 format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
416331ca 148 format!("not a {}", expected),
e74abb32
XL
149 span,
150 match res {
151 Res::Def(DefKind::Fn, _) => {
152 // Verify whether this is a fn call or an Fn used as a type.
dfeec247
XL
153 self.r
154 .session
155 .source_map()
156 .span_to_snippet(span)
157 .map(|snippet| snippet.ends_with(')'))
158 .unwrap_or(false)
e74abb32 159 }
ba9703b0
XL
160 Res::Def(
161 DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
162 _,
163 )
dfeec247
XL
164 | Res::SelfCtor(_)
165 | Res::PrimTy(_)
166 | Res::Local(_) => true,
e74abb32 167 _ => false,
dfeec247
XL
168 },
169 )
416331ca
XL
170 } else {
171 let item_span = path.last().unwrap().ident.span;
172 let (mod_prefix, mod_str) = if path.len() == 1 {
173 (String::new(), "this scope".to_string())
174 } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
6a06907d
XL
175 if self.r.session.edition() > Edition::Edition2015 {
176 // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
177 // which overrides all other expectations of item type
178 expected = "crate";
179 (String::new(), "the list of imported crates".to_string())
180 } else {
181 (String::new(), "the crate root".to_string())
182 }
183 } else if path.len() == 2 && path[0].ident.name == kw::Crate {
416331ca
XL
184 (String::new(), "the crate root".to_string())
185 } else {
186 let mod_path = &path[..path.len() - 1];
dfeec247
XL
187 let mod_prefix =
188 match self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No) {
189 PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
190 _ => None,
191 }
cdc7bbd5 192 .map_or_else(String::new, |res| format!("{} ", res.descr()));
416331ca
XL
193 (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
194 };
dfeec247
XL
195 (
196 format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
f9f354fc 197 if path_str == "async" && expected.starts_with("struct") {
5869c6ff 198 "`async` blocks are only allowed in Rust 2018 or later".to_string()
f9f354fc
XL
199 } else {
200 format!("not found in {}", mod_str)
201 },
e74abb32 202 item_span,
dfeec247
XL
203 false,
204 )
416331ca
XL
205 };
206
dfeec247 207 let code = source.error_code(res.is_some());
416331ca
XL
208 let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
209
1b1a35ee
XL
210 match (source, self.diagnostic_metadata.in_if_condition) {
211 (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
212 err.span_suggestion_verbose(
213 span.shrink_to_lo(),
214 "you might have meant to use pattern matching",
215 "let ".to_string(),
216 Applicability::MaybeIncorrect,
217 );
218 self.r.session.if_let_suggestions.borrow_mut().insert(*span);
219 }
220 _ => {}
221 }
222
3dfed10e 223 let is_assoc_fn = self.self_type_is_available(span);
416331ca 224 // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
3dfed10e 225 if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn {
f035d41b 226 err.span_suggestion_short(
416331ca 227 span,
f035d41b 228 "you might have meant to use `self` here instead",
416331ca
XL
229 "self".to_string(),
230 Applicability::MaybeIncorrect,
231 );
3dfed10e
XL
232 if !self.self_value_is_available(path[0].ident.span, span) {
233 if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
234 &self.diagnostic_metadata.current_function
235 {
236 let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
237 (param.span.shrink_to_lo(), "&self, ")
238 } else {
239 (
240 self.r
241 .session
242 .source_map()
243 .span_through_char(*fn_span, '(')
244 .shrink_to_hi(),
245 "&self",
246 )
247 };
248 err.span_suggestion_verbose(
249 span,
250 "if you meant to use `self`, you are also missing a `self` receiver \
251 argument",
252 sugg.to_string(),
253 Applicability::MaybeIncorrect,
254 );
255 }
256 }
416331ca
XL
257 }
258
259 // Emit special messages for unresolved `Self` and `self`.
260 if is_self_type(path, ns) {
dfeec247 261 err.code(rustc_errors::error_code!(E0411));
e74abb32
XL
262 err.span_label(
263 span,
74b04a01 264 "`Self` is only available in impls, traits, and type definitions".to_string(),
e74abb32 265 );
416331ca
XL
266 return (err, Vec::new());
267 }
268 if is_self_value(path, ns) {
269 debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
270
dfeec247 271 err.code(rustc_errors::error_code!(E0424));
416331ca 272 err.span_label(span, match source {
74b04a01
XL
273 PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed"
274 .to_string(),
275 _ => "`self` value is a keyword only available in methods with a `self` parameter"
276 .to_string(),
416331ca 277 });
f9f354fc
XL
278 if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
279 // The current function has a `self' parameter, but we were unable to resolve
280 // a reference to `self`. This can only happen if the `self` identifier we
281 // are resolving came from a different hygiene context.
5869c6ff 282 if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
f9f354fc
XL
283 err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
284 } else {
3dfed10e
XL
285 let doesnt = if is_assoc_fn {
286 let (span, sugg) = fn_kind
287 .decl()
288 .inputs
289 .get(0)
290 .map(|p| (p.span.shrink_to_lo(), "&self, "))
291 .unwrap_or_else(|| {
292 (
293 self.r
294 .session
295 .source_map()
296 .span_through_char(*span, '(')
297 .shrink_to_hi(),
298 "&self",
299 )
300 });
301 err.span_suggestion_verbose(
302 span,
303 "add a `self` receiver parameter to make the associated `fn` a method",
304 sugg.to_string(),
305 Applicability::MaybeIncorrect,
306 );
307 "doesn't"
308 } else {
309 "can't"
310 };
311 if let Some(ident) = fn_kind.ident() {
312 err.span_label(
313 ident.span,
314 &format!("this function {} have a `self` parameter", doesnt),
315 );
316 }
f9f354fc 317 }
e74abb32 318 }
416331ca
XL
319 return (err, Vec::new());
320 }
321
322 // Try to lookup name in more relaxed fashion for better error reporting.
323 let ident = path.last().unwrap().ident;
dfeec247
XL
324 let candidates = self
325 .r
f035d41b 326 .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
416331ca
XL
327 .drain(..)
328 .filter(|ImportSuggestion { did, .. }| {
329 match (did, res.and_then(|res| res.opt_def_id())) {
330 (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
331 _ => true,
332 }
333 })
334 .collect::<Vec<_>>();
335 let crate_def_id = DefId::local(CRATE_DEF_INDEX);
336 if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
6a06907d
XL
337 let mut enum_candidates: Vec<_> = self
338 .r
339 .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)
340 .into_iter()
341 .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
342 .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
343 .collect();
416331ca 344 if !enum_candidates.is_empty() {
3dfed10e
XL
345 if let (PathSource::Type, Some(span)) =
346 (source, self.diagnostic_metadata.current_type_ascription.last())
347 {
348 if self
349 .r
350 .session
351 .parse_sess
352 .type_ascription_path_suggestions
353 .borrow()
354 .contains(span)
355 {
356 // Already reported this issue on the lhs of the type ascription.
357 err.delay_as_bug();
358 return (err, candidates);
359 }
360 }
361
3dfed10e
XL
362 enum_candidates.sort();
363
416331ca
XL
364 // Contextualize for E0412 "cannot find type", but don't belabor the point
365 // (that it's a variant) for E0573 "expected type, found variant".
366 let preamble = if res.is_none() {
367 let others = match enum_candidates.len() {
368 1 => String::new(),
369 2 => " and 1 other".to_owned(),
dfeec247 370 n => format!(" and {} others", n),
416331ca 371 };
dfeec247 372 format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
416331ca
XL
373 } else {
374 String::new()
375 };
376 let msg = format!("{}try using the variant's enum", preamble);
377
378 err.span_suggestions(
379 span,
380 &msg,
6a06907d 381 enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),
416331ca
XL
382 Applicability::MachineApplicable,
383 );
384 }
385 }
386 if path.len() == 1 && self.self_type_is_available(span) {
387 if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
388 let self_is_available = self.self_value_is_available(path[0].ident.span, span);
389 match candidate {
390 AssocSuggestion::Field => {
391 if self_is_available {
392 err.span_suggestion(
393 span,
394 "you might have meant to use the available field",
395 format!("self.{}", path_str),
396 Applicability::MachineApplicable,
397 );
398 } else {
dfeec247 399 err.span_label(span, "a field by this name exists in `Self`");
416331ca
XL
400 }
401 }
402 AssocSuggestion::MethodWithSelf if self_is_available => {
403 err.span_suggestion(
404 span,
29967ef6 405 "you might have meant to call the method",
416331ca
XL
406 format!("self.{}", path_str),
407 Applicability::MachineApplicable,
408 );
409 }
29967ef6
XL
410 AssocSuggestion::MethodWithSelf
411 | AssocSuggestion::AssocFn
412 | AssocSuggestion::AssocConst
413 | AssocSuggestion::AssocType => {
416331ca
XL
414 err.span_suggestion(
415 span,
29967ef6 416 &format!("you might have meant to {}", candidate.action()),
416331ca
XL
417 format!("Self::{}", path_str),
418 Applicability::MachineApplicable,
419 );
420 }
421 }
422 return (err, candidates);
423 }
dfeec247
XL
424
425 // If the first argument in call is `self` suggest calling a method.
426 if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
427 let mut args_snippet = String::new();
428 if let Some(args_span) = args_span {
429 if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
430 args_snippet = snippet;
431 }
432 }
433
434 err.span_suggestion(
435 call_span,
436 &format!("try calling `{}` as a method", ident),
437 format!("self.{}({})", path_str, args_snippet),
438 Applicability::MachineApplicable,
439 );
440 return (err, candidates);
441 }
416331ca
XL
442 }
443
444 // Try Levenshtein algorithm.
e74abb32 445 let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected, span);
416331ca
XL
446 // Try context-dependent help if relaxed lookup didn't work.
447 if let Some(res) = res {
e74abb32
XL
448 if self.smart_resolve_context_dependent_help(
449 &mut err,
450 span,
451 source,
452 res,
453 &path_str,
454 &fallback_label,
455 ) {
3dfed10e
XL
456 // We do this to avoid losing a secondary span when we override the main error span.
457 self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
416331ca
XL
458 return (err, candidates);
459 }
460 }
461
cdc7bbd5 462 let is_macro = base_span.from_expansion() && base_span.desugaring_kind().is_none();
29967ef6
XL
463 if !self.type_ascription_suggestion(&mut err, base_span) {
464 let mut fallback = false;
465 if let (
466 PathSource::Trait(AliasPossibility::Maybe),
467 Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
cdc7bbd5
XL
468 false,
469 ) = (source, res, is_macro)
29967ef6
XL
470 {
471 if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
472 fallback = true;
473 let spans: Vec<Span> = bounds
474 .iter()
475 .map(|bound| bound.span())
476 .filter(|&sp| sp != base_span)
477 .collect();
478
479 let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
480 // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
481 let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
482 // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
483 let last_bound_span = spans.last().cloned().unwrap();
484 let mut multi_span: MultiSpan = spans.clone().into();
485 for sp in spans {
486 let msg = if sp == last_bound_span {
487 format!(
488 "...because of {} bound{}",
489 if bounds.len() <= 2 { "this" } else { "these" },
490 if bounds.len() <= 2 { "" } else { "s" },
491 )
492 } else {
493 String::new()
494 };
495 multi_span.push_span_label(sp, msg);
496 }
497 multi_span.push_span_label(
498 base_span,
499 "expected this type to be a trait...".to_string(),
e74abb32 500 );
29967ef6
XL
501 err.span_help(
502 multi_span,
503 "`+` is used to constrain a \"trait object\" type with lifetimes or \
504 auto-traits; structs and enums can't be bound in that way",
505 );
506 if bounds.iter().all(|bound| match bound {
507 ast::GenericBound::Outlives(_) => true,
508 ast::GenericBound::Trait(tr, _) => tr.span == base_span,
509 }) {
510 let mut sugg = vec![];
511 if base_span != start_span {
512 sugg.push((start_span.until(base_span), String::new()));
513 }
514 if base_span != end_span {
515 sugg.push((base_span.shrink_to_hi().to(end_span), String::new()));
516 }
517
518 err.multipart_suggestion(
519 "if you meant to use a type and not a trait here, remove the bounds",
520 sugg,
521 Applicability::MaybeIncorrect,
522 );
523 }
e74abb32 524 }
29967ef6
XL
525 }
526
527 fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
528
529 if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
530 fallback = true;
531 match self.diagnostic_metadata.current_let_binding {
532 Some((pat_sp, Some(ty_sp), None))
533 if ty_sp.contains(base_span) && could_be_expr =>
534 {
535 err.span_suggestion_short(
536 pat_sp.between(ty_sp),
537 "use `=` if you meant to assign",
538 " = ".to_string(),
539 Applicability::MaybeIncorrect,
540 );
541 }
542 _ => {}
543 }
544 }
545 if fallback {
546 // Fallback label.
547 err.span_label(base_span, fallback_label);
e74abb32 548 }
416331ca 549 }
fc512014
XL
550 if let Some(err_code) = &err.code {
551 if err_code == &rustc_errors::error_code!(E0425) {
552 for label_rib in &self.label_ribs {
5869c6ff 553 for (label_ident, node_id) in &label_rib.bindings {
fc512014 554 if format!("'{}", ident) == label_ident.to_string() {
5869c6ff
XL
555 err.span_label(label_ident.span, "a label with a similar name exists");
556 if let PathSource::Expr(Some(Expr {
557 kind: ExprKind::Break(None, Some(_)),
558 ..
559 })) = source
560 {
561 err.span_suggestion(
562 span,
563 "use the similarly named label",
564 label_ident.name.to_string(),
565 Applicability::MaybeIncorrect,
566 );
567 // Do not lint against unused label when we suggest them.
568 self.diagnostic_metadata.unused_labels.remove(node_id);
569 }
fc512014
XL
570 }
571 }
572 }
6a06907d
XL
573 } else if err_code == &rustc_errors::error_code!(E0412) {
574 if let Some(correct) = Self::likely_rust_type(path) {
575 err.span_suggestion(
576 span,
577 "perhaps you intended to use this type",
578 correct.to_string(),
579 Applicability::MaybeIncorrect,
580 );
581 }
fc512014
XL
582 }
583 }
584
416331ca
XL
585 (err, candidates)
586 }
587
29967ef6
XL
588 /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
589 fn restrict_assoc_type_in_where_clause(
590 &mut self,
591 span: Span,
592 err: &mut DiagnosticBuilder<'_>,
593 ) -> bool {
594 // Detect that we are actually in a `where` predicate.
595 let (bounded_ty, bounds, where_span) =
596 if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
597 bounded_ty,
598 bound_generic_params,
599 bounds,
600 span,
601 })) = self.diagnostic_metadata.current_where_predicate
602 {
603 if !bound_generic_params.is_empty() {
604 return false;
605 }
606 (bounded_ty, bounds, span)
607 } else {
608 return false;
609 };
610
611 // Confirm that the target is an associated type.
612 let (ty, position, path) = if let ast::TyKind::Path(
613 Some(ast::QSelf { ty, position, .. }),
614 path,
615 ) = &bounded_ty.kind
616 {
617 // use this to verify that ident is a type param.
618 let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
619 bounded_ty.id,
620 None,
621 &Segment::from_path(path),
622 Namespace::TypeNS,
623 span,
624 true,
625 CrateLint::No,
626 ) {
627 partial_res
628 } else {
629 return false;
630 };
631 if !(matches!(
632 partial_res.base_res(),
633 hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
634 ) && partial_res.unresolved_segments() == 0)
635 {
636 return false;
637 }
638 (ty, position, path)
639 } else {
640 return false;
641 };
642
643 if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
644 // Confirm that the `SelfTy` is a type parameter.
645 let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
646 bounded_ty.id,
647 None,
648 &Segment::from_path(type_param_path),
649 Namespace::TypeNS,
650 span,
651 true,
652 CrateLint::No,
653 ) {
654 partial_res
655 } else {
656 return false;
657 };
658 if !(matches!(
659 partial_res.base_res(),
660 hir::def::Res::Def(hir::def::DefKind::TyParam, _)
661 ) && partial_res.unresolved_segments() == 0)
662 {
663 return false;
664 }
665 if let (
666 [ast::PathSegment { ident: constrain_ident, args: None, .. }],
667 [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)],
668 ) = (&type_param_path.segments[..], &bounds[..])
669 {
670 if let [ast::PathSegment { ident, args: None, .. }] =
671 &poly_trait_ref.trait_ref.path.segments[..]
672 {
673 if ident.span == span {
674 err.span_suggestion_verbose(
675 *where_span,
676 &format!("constrain the associated type to `{}`", ident),
677 format!(
678 "{}: {}<{} = {}>",
679 self.r
680 .session
681 .source_map()
682 .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
683 .unwrap_or_else(|_| constrain_ident.to_string()),
684 path.segments[..*position]
685 .iter()
686 .map(|segment| path_segment_to_string(segment))
687 .collect::<Vec<_>>()
688 .join("::"),
689 path.segments[*position..]
690 .iter()
691 .map(|segment| path_segment_to_string(segment))
692 .collect::<Vec<_>>()
693 .join("::"),
694 ident,
695 ),
696 Applicability::MaybeIncorrect,
697 );
698 }
699 return true;
700 }
701 }
702 }
703 false
704 }
705
dfeec247
XL
706 /// Check if the source is call expression and the first argument is `self`. If true,
707 /// return the span of whole call and the span for all arguments expect the first one (`self`).
708 fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
709 let mut has_self_arg = None;
3dfed10e
XL
710 if let PathSource::Expr(Some(parent)) = source {
711 match &parent.kind {
74b04a01 712 ExprKind::Call(_, args) if !args.is_empty() => {
dfeec247
XL
713 let mut expr_kind = &args[0].kind;
714 loop {
715 match expr_kind {
716 ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
717 if arg_name.segments[0].ident.name == kw::SelfLower {
3dfed10e 718 let call_span = parent.span;
dfeec247
XL
719 let tail_args_span = if args.len() > 1 {
720 Some(Span::new(
721 args[1].span.lo(),
722 args.last().unwrap().span.hi(),
723 call_span.ctxt(),
724 ))
725 } else {
726 None
727 };
728 has_self_arg = Some((call_span, tail_args_span));
729 }
730 break;
731 }
732 ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
733 _ => break,
734 }
735 }
736 }
737 _ => (),
738 }
739 };
ba9703b0 740 has_self_arg
dfeec247
XL
741 }
742
f9f354fc 743 fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
416331ca
XL
744 // HACK(estebank): find a better way to figure out that this was a
745 // parser issue where a struct literal is being used on an expression
746 // where a brace being opened means a block is being started. Look
747 // ahead for the next text to see if `span` is followed by a `{`.
748 let sm = self.r.session.source_map();
749 let mut sp = span;
750 loop {
751 sp = sm.next_point(sp);
752 match sm.span_to_snippet(sp) {
753 Ok(ref snippet) => {
dfeec247 754 if snippet.chars().any(|c| !c.is_whitespace()) {
416331ca
XL
755 break;
756 }
757 }
758 _ => break,
759 }
760 }
29967ef6 761 let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
416331ca 762 // In case this could be a struct literal that needs to be surrounded
f9f354fc 763 // by parentheses, find the appropriate span.
416331ca
XL
764 let mut i = 0;
765 let mut closing_brace = None;
766 loop {
767 sp = sm.next_point(sp);
768 match sm.span_to_snippet(sp) {
769 Ok(ref snippet) => {
770 if snippet == "}" {
f9f354fc 771 closing_brace = Some(span.to(sp));
416331ca
XL
772 break;
773 }
774 }
775 _ => break,
776 }
777 i += 1;
778 // The bigger the span, the more likely we're incorrect --
779 // bound it to 100 chars long.
780 if i > 100 {
781 break;
782 }
783 }
ba9703b0 784 (followed_by_brace, closing_brace)
416331ca
XL
785 }
786
787 /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
788 /// function.
789 /// Returns `true` if able to provide context-dependent help.
790 fn smart_resolve_context_dependent_help(
791 &mut self,
792 err: &mut DiagnosticBuilder<'a>,
793 span: Span,
794 source: PathSource<'_>,
795 res: Res,
796 path_str: &str,
797 fallback_label: &str,
798 ) -> bool {
799 let ns = source.namespace();
800 let is_expected = &|res| source.is_expected(res);
801
e74abb32 802 let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
416331ca
XL
803 ExprKind::Field(_, ident) => {
804 err.span_suggestion(
805 expr.span,
806 "use the path separator to refer to an item",
807 format!("{}::{}", path_str, ident),
808 Applicability::MaybeIncorrect,
809 );
810 true
811 }
812 ExprKind::MethodCall(ref segment, ..) => {
813 let span = expr.span.with_hi(segment.ident.span.hi());
814 err.span_suggestion(
815 span,
816 "use the path separator to refer to an item",
817 format!("{}::{}", path_str, segment.ident),
818 Applicability::MaybeIncorrect,
819 );
820 true
821 }
822 _ => false,
823 };
824
17df50a5
XL
825 let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| {
826 match source {
827 PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
828 | PathSource::TupleStruct(span, _) => {
829 // We want the main underline to cover the suggested code as well for
830 // cleaner output.
831 err.set_span(*span);
832 *span
833 }
834 _ => span,
835 }
836 };
837
e74abb32 838 let mut bad_struct_syntax_suggestion = |def_id: DefId| {
416331ca 839 let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
3dfed10e 840
416331ca 841 match source {
3dfed10e
XL
842 PathSource::Expr(Some(
843 parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
844 )) if path_sep(err, &parent) => {}
845 PathSource::Expr(
846 None
847 | Some(Expr {
848 kind:
849 ExprKind::Path(..)
850 | ExprKind::Binary(..)
851 | ExprKind::Unary(..)
852 | ExprKind::If(..)
853 | ExprKind::While(..)
854 | ExprKind::ForLoop(..)
855 | ExprKind::Match(..),
856 ..
857 }),
858 ) if followed_by_brace => {
f9f354fc 859 if let Some(sp) = closing_brace {
3dfed10e 860 err.span_label(span, fallback_label);
f9f354fc
XL
861 err.multipart_suggestion(
862 "surround the struct literal with parentheses",
863 vec![
864 (sp.shrink_to_lo(), "(".to_string()),
865 (sp.shrink_to_hi(), ")".to_string()),
866 ],
416331ca
XL
867 Applicability::MaybeIncorrect,
868 );
869 } else {
870 err.span_label(
f9f354fc
XL
871 span, // Note the parentheses surrounding the suggestion below
872 format!(
873 "you might want to surround a struct literal with parentheses: \
874 `({} {{ /* fields */ }})`?",
875 path_str
876 ),
416331ca
XL
877 );
878 }
dfeec247 879 }
1b1a35ee 880 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
17df50a5 881 let span = find_span(&source, err);
3dfed10e
XL
882 if let Some(span) = self.def_span(def_id) {
883 err.span_label(span, &format!("`{}` defined here", path_str));
884 }
885 let (tail, descr, applicability) = match source {
1b1a35ee 886 PathSource::Pat | PathSource::TupleStruct(..) => {
3dfed10e
XL
887 ("", "pattern", Applicability::MachineApplicable)
888 }
889 _ => (": val", "literal", Applicability::HasPlaceholders),
890 };
891 let (fields, applicability) = match self.r.field_names.get(&def_id) {
892 Some(fields) => (
893 fields
894 .iter()
895 .map(|f| format!("{}{}", f.node, tail))
896 .collect::<Vec<String>>()
897 .join(", "),
898 applicability,
899 ),
900 None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
901 };
902 let pad = match self.r.field_names.get(&def_id) {
903 Some(fields) if fields.is_empty() => "",
904 _ => " ",
905 };
906 err.span_suggestion(
907 span,
908 &format!("use struct {} syntax instead", descr),
29967ef6 909 format!("{path_str} {{{pad}{fields}{pad}}}"),
3dfed10e
XL
910 applicability,
911 );
912 }
913 _ => {
914 err.span_label(span, fallback_label);
e74abb32 915 }
416331ca
XL
916 }
917 };
918
919 match (res, source) {
920 (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
3dfed10e 921 err.span_label(span, fallback_label);
ba9703b0
XL
922 err.span_suggestion_verbose(
923 span.shrink_to_hi(),
416331ca 924 "use `!` to invoke the macro",
ba9703b0 925 "!".to_string(),
416331ca
XL
926 Applicability::MaybeIncorrect,
927 );
928 if path_str == "try" && span.rust_2015() {
5869c6ff 929 err.note("if you want the `try` keyword, you need Rust 2018 or later");
416331ca
XL
930 }
931 }
f9f354fc 932 (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
416331ca 933 err.span_label(span, "type aliases cannot be used as traits");
fc512014 934 if self.r.session.is_nightly_build() {
f9f354fc
XL
935 let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
936 `type` alias";
3dfed10e 937 if let Some(span) = self.def_span(def_id) {
cdc7bbd5
XL
938 if let Ok(snip) = self.r.session.source_map().span_to_snippet(span) {
939 // The span contains a type alias so we should be able to
940 // replace `type` with `trait`.
941 let snip = snip.replacen("type", "trait", 1);
942 err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect);
943 } else {
944 err.span_help(span, msg);
945 }
f9f354fc
XL
946 } else {
947 err.help(msg);
948 }
416331ca
XL
949 }
950 }
951 (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
952 if !path_sep(err, &parent) {
953 return false;
954 }
955 }
3dfed10e
XL
956 (
957 Res::Def(DefKind::Enum, def_id),
1b1a35ee 958 PathSource::TupleStruct(..) | PathSource::Expr(..),
3dfed10e
XL
959 ) => {
960 if self
961 .diagnostic_metadata
962 .current_type_ascription
963 .last()
964 .map(|sp| {
965 self.r
966 .session
967 .parse_sess
968 .type_ascription_path_suggestions
969 .borrow()
970 .contains(&sp)
971 })
972 .unwrap_or(false)
973 {
974 err.delay_as_bug();
975 // We already suggested changing `:` into `::` during parsing.
976 return false;
977 }
416331ca 978
29967ef6 979 self.suggest_using_enum_variant(err, source, def_id, span);
e1599b0c 980 }
416331ca 981 (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
29967ef6
XL
982 let (ctor_def, ctor_vis, fields) =
983 if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
984 struct_ctor
985 } else {
986 bad_struct_syntax_suggestion(def_id);
987 return true;
988 };
1b1a35ee 989
29967ef6
XL
990 let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
991 if !is_expected(ctor_def) || is_accessible {
992 return true;
993 }
994
995 let field_spans = match source {
996 // e.g. `if let Enum::TupleVariant(field1, field2) = _`
997 PathSource::TupleStruct(_, pattern_spans) => {
998 err.set_primary_message(
999 "cannot match against a tuple struct which contains private fields",
1000 );
1001
1002 // Use spans of the tuple struct pattern.
1003 Some(Vec::from(pattern_spans))
416331ca 1004 }
29967ef6
XL
1005 // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1006 _ if source.is_call() => {
1007 err.set_primary_message(
1008 "cannot initialize a tuple struct which contains private fields",
1009 );
1010
1011 // Use spans of the tuple struct definition.
1012 self.r
1013 .field_names
1014 .get(&def_id)
1015 .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1016 }
1017 _ => None,
1018 };
1019
1020 if let Some(spans) =
1021 field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
1022 {
cdc7bbd5 1023 let non_visible_spans: Vec<Span> = iter::zip(&fields, &spans)
29967ef6
XL
1024 .filter(|(vis, _)| {
1025 !self.r.is_accessible_from(**vis, self.parent_scope.module)
1026 })
1027 .map(|(_, span)| *span)
1028 .collect();
1029
1030 if non_visible_spans.len() > 0 {
1031 let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into();
1032 non_visible_spans
1033 .into_iter()
1034 .for_each(|s| m.push_span_label(s, "private field".to_string()));
1035 err.span_note(m, "constructor is not visible here due to private fields");
1036 }
1037
1038 return true;
416331ca 1039 }
29967ef6
XL
1040
1041 err.span_label(
1042 span,
1043 "constructor is not visible here due to private fields".to_string(),
1044 );
416331ca 1045 }
ba9703b0
XL
1046 (
1047 Res::Def(
1048 DefKind::Union | DefKind::Variant | DefKind::Ctor(_, CtorKind::Fictive),
1049 def_id,
1050 ),
1051 _,
1052 ) if ns == ValueNS => {
e74abb32 1053 bad_struct_syntax_suggestion(def_id);
416331ca 1054 }
17df50a5
XL
1055 (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
1056 match source {
1057 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1058 let span = find_span(&source, err);
1059 if let Some(span) = self.def_span(def_id) {
1060 err.span_label(span, &format!("`{}` defined here", path_str));
1061 }
1062 err.span_suggestion(
1063 span,
1064 &format!("use this syntax instead"),
1065 format!("{path_str}"),
1066 Applicability::MaybeIncorrect,
1067 );
1068 }
1069 _ => return false,
1070 }
1071 }
e74abb32 1072 (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
3dfed10e 1073 if let Some(span) = self.def_span(def_id) {
e74abb32
XL
1074 err.span_label(span, &format!("`{}` defined here", path_str));
1075 }
cdc7bbd5
XL
1076 let fields = self.r.field_names.get(&def_id).map_or_else(
1077 || "/* fields */".to_string(),
1078 |fields| vec!["_"; fields.len()].join(", "),
1079 );
3dfed10e
XL
1080 err.span_suggestion(
1081 span,
1082 "use the tuple variant pattern syntax instead",
1083 format!("{}({})", path_str, fields),
1084 Applicability::HasPlaceholders,
1085 );
e1599b0c 1086 }
416331ca
XL
1087 (Res::SelfTy(..), _) if ns == ValueNS => {
1088 err.span_label(span, fallback_label);
1089 err.note("can't use `Self` as a constructor, you must use the implemented struct");
1090 }
ba9703b0 1091 (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
416331ca
XL
1092 err.note("can't use a type alias as a constructor");
1093 }
1094 _ => return false,
1095 }
1096 true
1097 }
1098
dfeec247
XL
1099 fn lookup_assoc_candidate<FilterFn>(
1100 &mut self,
1101 ident: Ident,
1102 ns: Namespace,
1103 filter_fn: FilterFn,
1104 ) -> Option<AssocSuggestion>
1105 where
1106 FilterFn: Fn(Res) -> bool,
416331ca
XL
1107 {
1108 fn extract_node_id(t: &Ty) -> Option<NodeId> {
e74abb32 1109 match t.kind {
416331ca
XL
1110 TyKind::Path(None, _) => Some(t.id),
1111 TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
1112 // This doesn't handle the remaining `Ty` variants as they are not
1113 // that commonly the self_type, it might be interesting to provide
1114 // support for those in future.
1115 _ => None,
1116 }
1117 }
1118
1119 // Fields are generally expected in the same contexts as locals.
1120 if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
dfeec247
XL
1121 if let Some(node_id) =
1122 self.diagnostic_metadata.current_self_type.as_ref().and_then(extract_node_id)
e74abb32 1123 {
416331ca
XL
1124 // Look for a field with the same name in the current self_type.
1125 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
1126 match resolution.base_res() {
ba9703b0 1127 Res::Def(DefKind::Struct | DefKind::Union, did)
dfeec247
XL
1128 if resolution.unresolved_segments() == 0 =>
1129 {
416331ca 1130 if let Some(field_names) = self.r.field_names.get(&did) {
dfeec247
XL
1131 if field_names
1132 .iter()
1133 .any(|&field_name| ident.name == field_name.node)
1134 {
416331ca
XL
1135 return Some(AssocSuggestion::Field);
1136 }
1137 }
1138 }
1139 _ => {}
1140 }
1141 }
1142 }
1143 }
1144
29967ef6 1145 if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
6a06907d 1146 for assoc_item in items {
29967ef6
XL
1147 if assoc_item.ident == ident {
1148 return Some(match &assoc_item.kind {
1149 ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
5869c6ff
XL
1150 ast::AssocItemKind::Fn(box ast::FnKind(_, sig, ..))
1151 if sig.decl.has_self() =>
1152 {
29967ef6
XL
1153 AssocSuggestion::MethodWithSelf
1154 }
1155 ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
1156 ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType,
1157 ast::AssocItemKind::MacCall(_) => continue,
1158 });
1159 }
416331ca
XL
1160 }
1161 }
1162
1163 // Look for associated items in the current trait.
1164 if let Some((module, _)) = self.current_trait_ref {
1165 if let Ok(binding) = self.r.resolve_ident_in_module(
dfeec247
XL
1166 ModuleOrUniformRoot::Module(module),
1167 ident,
1168 ns,
1169 &self.parent_scope,
1170 false,
1171 module.span,
1172 ) {
416331ca
XL
1173 let res = binding.res();
1174 if filter_fn(res) {
29967ef6
XL
1175 if self.r.has_self.contains(&res.def_id()) {
1176 return Some(AssocSuggestion::MethodWithSelf);
416331ca 1177 } else {
29967ef6
XL
1178 match res {
1179 Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
1180 Res::Def(DefKind::AssocConst, _) => {
1181 return Some(AssocSuggestion::AssocConst);
1182 }
1183 Res::Def(DefKind::AssocTy, _) => {
1184 return Some(AssocSuggestion::AssocType);
1185 }
1186 _ => {}
1187 }
1188 }
416331ca
XL
1189 }
1190 }
1191 }
1192
1193 None
1194 }
1195
1196 fn lookup_typo_candidate(
1197 &mut self,
1198 path: &[Segment],
1199 ns: Namespace,
1200 filter_fn: &impl Fn(Res) -> bool,
1201 span: Span,
1202 ) -> Option<TypoSuggestion> {
1203 let mut names = Vec::new();
1204 if path.len() == 1 {
1205 // Search in lexical scope.
1206 // Walk backwards up the ribs in scope and collect candidates.
1207 for rib in self.ribs[ns].iter().rev() {
1208 // Locals and type parameters
1209 for (ident, &res) in &rib.bindings {
1210 if filter_fn(res) {
1211 names.push(TypoSuggestion::from_res(ident.name, res));
1212 }
1213 }
1214 // Items in scope
1215 if let RibKind::ModuleRibKind(module) = rib.kind {
1216 // Items from this module
e1599b0c 1217 self.r.add_module_candidates(module, &mut names, &filter_fn);
416331ca
XL
1218
1219 if let ModuleKind::Block(..) = module.kind {
1220 // We can see through blocks
1221 } else {
1222 // Items from the prelude
1223 if !module.no_implicit_prelude {
1224 let extern_prelude = self.r.extern_prelude.clone();
1225 names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
3dfed10e
XL
1226 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
1227 |crate_id| {
416331ca
XL
1228 let crate_mod = Res::Def(
1229 DefKind::Mod,
dfeec247 1230 DefId { krate: crate_id, index: CRATE_DEF_INDEX },
416331ca
XL
1231 );
1232
1233 if filter_fn(crate_mod) {
1234 Some(TypoSuggestion::from_res(ident.name, crate_mod))
1235 } else {
1236 None
1237 }
3dfed10e
XL
1238 },
1239 )
416331ca
XL
1240 }));
1241
1242 if let Some(prelude) = self.r.prelude {
e1599b0c 1243 self.r.add_module_candidates(prelude, &mut names, &filter_fn);
416331ca
XL
1244 }
1245 }
1246 break;
1247 }
1248 }
1249 }
1250 // Add primitive types to the mix
1251 if filter_fn(Res::PrimTy(PrimTy::Bool)) {
1252 names.extend(
6a06907d
XL
1253 PrimTy::ALL.iter().map(|prim_ty| {
1254 TypoSuggestion::from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
dfeec247 1255 }),
416331ca
XL
1256 )
1257 }
1258 } else {
1259 // Search in module.
1260 let mod_path = &path[..path.len() - 1];
dfeec247
XL
1261 if let PathResult::Module(module) =
1262 self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
1263 {
416331ca 1264 if let ModuleOrUniformRoot::Module(module) = module {
e1599b0c 1265 self.r.add_module_candidates(module, &mut names, &filter_fn);
416331ca
XL
1266 }
1267 }
1268 }
1269
1270 let name = path[path.len() - 1].ident.name;
1271 // Make sure error reporting is deterministic.
1272 names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
1273
1274 match find_best_match_for_name(
fc512014 1275 &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
3dfed10e 1276 name,
416331ca
XL
1277 None,
1278 ) {
dfeec247
XL
1279 Some(found) if found != name => {
1280 names.into_iter().find(|suggestion| suggestion.candidate == found)
1281 }
416331ca
XL
1282 _ => None,
1283 }
1284 }
1285
6a06907d
XL
1286 // Returns the name of the Rust type approximately corresponding to
1287 // a type name in another programming language.
1288 fn likely_rust_type(path: &[Segment]) -> Option<Symbol> {
1289 let name = path[path.len() - 1].ident.as_str();
1290 // Common Java types
1291 Some(match &*name {
1292 "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
1293 "short" => sym::i16,
1294 "boolean" => sym::bool,
1295 "int" => sym::i32,
1296 "long" => sym::i64,
1297 "float" => sym::f32,
1298 "double" => sym::f64,
1299 _ => return None,
1300 })
1301 }
1302
416331ca
XL
1303 /// Only used in a specific case of type ascription suggestions
1304 fn get_colon_suggestion_span(&self, start: Span) -> Span {
74b04a01
XL
1305 let sm = self.r.session.source_map();
1306 start.to(sm.next_point(start))
416331ca
XL
1307 }
1308
3dfed10e 1309 fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool {
74b04a01
XL
1310 let sm = self.r.session.source_map();
1311 let base_snippet = sm.span_to_snippet(base_span);
3dfed10e
XL
1312 if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
1313 if let Ok(snippet) = sm.span_to_snippet(sp) {
1314 let len = snippet.trim_end().len() as u32;
1315 if snippet.trim() == ":" {
1316 let colon_sp =
1317 sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
1318 let mut show_label = true;
1319 if sm.is_multiline(sp) {
1320 err.span_suggestion_short(
1321 colon_sp,
1322 "maybe you meant to write `;` here",
1323 ";".to_string(),
1324 Applicability::MaybeIncorrect,
1325 );
1326 } else {
1327 let after_colon_sp =
1328 self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
1329 if snippet.len() == 1 {
1330 // `foo:bar`
1331 err.span_suggestion(
1332 colon_sp,
1333 "maybe you meant to write a path separator here",
1334 "::".to_string(),
416331ca
XL
1335 Applicability::MaybeIncorrect,
1336 );
3dfed10e
XL
1337 show_label = false;
1338 if !self
1339 .r
1340 .session
1341 .parse_sess
1342 .type_ascription_path_suggestions
1343 .borrow_mut()
1344 .insert(colon_sp)
416331ca 1345 {
3dfed10e 1346 err.delay_as_bug();
416331ca 1347 }
3dfed10e
XL
1348 }
1349 if let Ok(base_snippet) = base_snippet {
1350 let mut sp = after_colon_sp;
1351 for _ in 0..100 {
1352 // Try to find an assignment
1353 sp = sm.next_point(sp);
1354 let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
1355 match snippet {
1356 Ok(ref x) if x.as_str() == "=" => {
1357 err.span_suggestion(
1358 base_span,
1359 "maybe you meant to write an assignment here",
1360 format!("let {}", base_snippet),
1361 Applicability::MaybeIncorrect,
1362 );
1363 show_label = false;
1364 break;
416331ca 1365 }
3dfed10e
XL
1366 Ok(ref x) if x.as_str() == "\n" => break,
1367 Err(_) => break,
1368 Ok(_) => {}
416331ca
XL
1369 }
1370 }
1371 }
416331ca 1372 }
3dfed10e
XL
1373 if show_label {
1374 err.span_label(
1375 base_span,
1376 "expecting a type here because of type ascription",
1377 );
1378 }
1379 return show_label;
416331ca
XL
1380 }
1381 }
1382 }
3dfed10e 1383 false
416331ca
XL
1384 }
1385
1386 fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
1387 let mut result = None;
1388 let mut seen_modules = FxHashSet::default();
1389 let mut worklist = vec![(self.r.graph_root, Vec::new())];
1390
1391 while let Some((in_module, path_segments)) = worklist.pop() {
1392 // abort if the module is already found
dfeec247
XL
1393 if result.is_some() {
1394 break;
1395 }
416331ca 1396
e74abb32 1397 in_module.for_each_child(self.r, |_, ident, _, name_binding| {
416331ca
XL
1398 // abort if the module is already found or if name_binding is private external
1399 if result.is_some() || !name_binding.vis.is_visible_locally() {
dfeec247 1400 return;
416331ca
XL
1401 }
1402 if let Some(module) = name_binding.module() {
1403 // form the path
1404 let mut path_segments = path_segments.clone();
1405 path_segments.push(ast::PathSegment::from_ident(ident));
1406 let module_def_id = module.def_id().unwrap();
1407 if module_def_id == def_id {
1b1a35ee
XL
1408 let path =
1409 Path { span: name_binding.span, segments: path_segments, tokens: None };
f9f354fc
XL
1410 result = Some((
1411 module,
f035d41b
XL
1412 ImportSuggestion {
1413 did: Some(def_id),
1414 descr: "module",
1415 path,
1416 accessible: true,
1417 },
f9f354fc 1418 ));
416331ca
XL
1419 } else {
1420 // add the module to the lookup
1421 if seen_modules.insert(module_def_id) {
1422 worklist.push((module, path_segments));
1423 }
1424 }
1425 }
1426 });
1427 }
1428
1429 result
1430 }
1431
29967ef6 1432 fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
416331ca 1433 self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
416331ca 1434 let mut variants = Vec::new();
e74abb32 1435 enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
29967ef6 1436 if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
416331ca
XL
1437 let mut segms = enum_import_suggestion.path.segments.clone();
1438 segms.push(ast::PathSegment::from_ident(ident));
29967ef6
XL
1439 let path = Path { span: name_binding.span, segments: segms, tokens: None };
1440 variants.push((path, def_id, kind));
416331ca
XL
1441 }
1442 });
1443 variants
1444 })
1445 }
dfeec247 1446
29967ef6
XL
1447 /// Adds a suggestion for using an enum's variant when an enum is used instead.
1448 fn suggest_using_enum_variant(
1449 &mut self,
1450 err: &mut DiagnosticBuilder<'a>,
1451 source: PathSource<'_>,
1452 def_id: DefId,
1453 span: Span,
1454 ) {
1455 let variants = match self.collect_enum_ctors(def_id) {
1456 Some(variants) => variants,
1457 None => {
1458 err.note("you might have meant to use one of the enum's variants");
1459 return;
1460 }
1461 };
1462
1463 let suggest_only_tuple_variants =
1464 matches!(source, PathSource::TupleStruct(..)) || source.is_call();
1465 if suggest_only_tuple_variants {
1466 // Suggest only tuple variants regardless of whether they have fields and do not
1467 // suggest path with added parenthesis.
1468 let mut suggestable_variants = variants
1469 .iter()
1470 .filter(|(.., kind)| *kind == CtorKind::Fn)
1471 .map(|(variant, ..)| path_names_to_string(variant))
1472 .collect::<Vec<_>>();
1473
1474 let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
1475
1476 let source_msg = if source.is_call() {
1477 "to construct"
1478 } else if matches!(source, PathSource::TupleStruct(..)) {
1479 "to match against"
1480 } else {
1481 unreachable!()
1482 };
1483
1484 if !suggestable_variants.is_empty() {
1485 let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
1486 format!("try {} the enum's variant", source_msg)
1487 } else {
1488 format!("try {} one of the enum's variants", source_msg)
1489 };
1490
1491 err.span_suggestions(
1492 span,
1493 &msg,
1494 suggestable_variants.drain(..),
1495 Applicability::MaybeIncorrect,
1496 );
1497 }
1498
1499 // If the enum has no tuple variants..
1500 if non_suggestable_variant_count == variants.len() {
1501 err.help(&format!("the enum has no tuple variants {}", source_msg));
1502 }
1503
1504 // If there are also non-tuple variants..
1505 if non_suggestable_variant_count == 1 {
1506 err.help(&format!(
1507 "you might have meant {} the enum's non-tuple variant",
1508 source_msg
1509 ));
1510 } else if non_suggestable_variant_count >= 1 {
1511 err.help(&format!(
1512 "you might have meant {} one of the enum's non-tuple variants",
1513 source_msg
1514 ));
1515 }
1516 } else {
1517 let needs_placeholder = |def_id: DefId, kind: CtorKind| {
5869c6ff 1518 let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
29967ef6
XL
1519 match kind {
1520 CtorKind::Const => false,
1521 CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
1522 _ => true,
1523 }
1524 };
1525
1526 let mut suggestable_variants = variants
1527 .iter()
1528 .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
1529 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1530 .map(|(variant, kind)| match kind {
1531 CtorKind::Const => variant,
1532 CtorKind::Fn => format!("({}())", variant),
1533 CtorKind::Fictive => format!("({} {{}})", variant),
1534 })
1535 .collect::<Vec<_>>();
1536
1537 if !suggestable_variants.is_empty() {
1538 let msg = if suggestable_variants.len() == 1 {
1539 "you might have meant to use the following enum variant"
1540 } else {
1541 "you might have meant to use one of the following enum variants"
1542 };
1543
1544 err.span_suggestions(
1545 span,
1546 msg,
1547 suggestable_variants.drain(..),
1548 Applicability::MaybeIncorrect,
1549 );
1550 }
1551
1552 let mut suggestable_variants_with_placeholders = variants
1553 .iter()
1554 .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
1555 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
1556 .filter_map(|(variant, kind)| match kind {
1557 CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
1558 CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
1559 _ => None,
1560 })
1561 .collect::<Vec<_>>();
1562
1563 if !suggestable_variants_with_placeholders.is_empty() {
1564 let msg = match (
1565 suggestable_variants.is_empty(),
1566 suggestable_variants_with_placeholders.len(),
1567 ) {
1568 (true, 1) => "the following enum variant is available",
1569 (true, _) => "the following enum variants are available",
1570 (false, 1) => "alternatively, the following enum variant is available",
1571 (false, _) => "alternatively, the following enum variants are also available",
1572 };
1573
1574 err.span_suggestions(
1575 span,
1576 msg,
1577 suggestable_variants_with_placeholders.drain(..),
1578 Applicability::HasPlaceholders,
1579 );
1580 }
1581 };
1582
1583 if def_id.is_local() {
1584 if let Some(span) = self.def_span(def_id) {
1585 err.span_note(span, "the enum is defined here");
1586 }
1587 }
1588 }
1589
dfeec247
XL
1590 crate fn report_missing_type_error(
1591 &self,
1592 path: &[Segment],
1593 ) -> Option<(Span, &'static str, String, Applicability)> {
f035d41b
XL
1594 let (ident, span) = match path {
1595 [segment] if !segment.has_generic_args => {
1596 (segment.ident.to_string(), segment.ident.span)
1597 }
dfeec247
XL
1598 _ => return None,
1599 };
f035d41b
XL
1600 let mut iter = ident.chars().map(|c| c.is_uppercase());
1601 let single_uppercase_char =
1602 matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
1603 if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
1604 return None;
1605 }
17df50a5
XL
1606 match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
1607 (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
dfeec247
XL
1608 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
1609 }
f035d41b
XL
1610 (
1611 Some(Item {
1612 kind:
1613 kind @ ItemKind::Fn(..)
1614 | kind @ ItemKind::Enum(..)
1615 | kind @ ItemKind::Struct(..)
1616 | kind @ ItemKind::Union(..),
1617 ..
1618 }),
17df50a5 1619 true, _
f035d41b 1620 )
17df50a5
XL
1621 // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
1622 | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
1623 | (Some(Item { kind, .. }), false, _) => {
dfeec247
XL
1624 // Likely missing type parameter.
1625 if let Some(generics) = kind.generics() {
f035d41b
XL
1626 if span.overlaps(generics.span) {
1627 // Avoid the following:
1628 // error[E0405]: cannot find trait `A` in this scope
1629 // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
1630 // |
1631 // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
1632 // | ^- help: you might be missing a type parameter: `, A`
1633 // | |
1634 // | not found in this scope
1635 return None;
1636 }
dfeec247
XL
1637 let msg = "you might be missing a type parameter";
1638 let (span, sugg) = if let [.., param] = &generics.params[..] {
1639 let span = if let [.., bound] = &param.bounds[..] {
1640 bound.span()
17df50a5
XL
1641 } else if let GenericParam {
1642 kind: GenericParamKind::Const { ty, kw_span: _, default }, ..
1643 } = param {
1644 default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
dfeec247
XL
1645 } else {
1646 param.ident.span
1647 };
1648 (span, format!(", {}", ident))
1649 } else {
1650 (generics.span, format!("<{}>", ident))
1651 };
1652 // Do not suggest if this is coming from macro expansion.
1653 if !span.from_expansion() {
1654 return Some((
1655 span.shrink_to_hi(),
1656 msg,
1657 sugg,
1658 Applicability::MaybeIncorrect,
1659 ));
1660 }
1661 }
1662 }
1663 _ => {}
1664 }
1665 None
1666 }
f035d41b
XL
1667
1668 /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
1669 /// optionally returning the closest match and whether it is reachable.
1670 crate fn suggestion_for_label_in_rib(
1671 &self,
1672 rib_index: usize,
1673 label: Ident,
1674 ) -> Option<LabelSuggestion> {
1675 // Are ribs from this `rib_index` within scope?
1676 let within_scope = self.is_label_valid_from_rib(rib_index);
1677
1678 let rib = &self.label_ribs[rib_index];
1679 let names = rib
1680 .bindings
1681 .iter()
1682 .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
fc512014
XL
1683 .map(|(id, _)| id.name)
1684 .collect::<Vec<Symbol>>();
f035d41b 1685
fc512014 1686 find_best_match_for_name(&names, label.name, None).map(|symbol| {
f035d41b
XL
1687 // Upon finding a similar name, get the ident that it was from - the span
1688 // contained within helps make a useful diagnostic. In addition, determine
1689 // whether this candidate is within scope.
1690 let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
1691 (*ident, within_scope)
1692 })
1693 }
416331ca 1694}
74b04a01
XL
1695
1696impl<'tcx> LifetimeContext<'_, 'tcx> {
1697 crate fn report_missing_lifetime_specifiers(
1698 &self,
17df50a5 1699 spans: Vec<Span>,
74b04a01
XL
1700 count: usize,
1701 ) -> DiagnosticBuilder<'tcx> {
1702 struct_span_err!(
1703 self.tcx.sess,
17df50a5 1704 spans,
74b04a01
XL
1705 E0106,
1706 "missing lifetime specifier{}",
1707 pluralize!(count)
1708 )
1709 }
1710
1711 crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
1712 let mut err = struct_span_err!(
1713 self.tcx.sess,
1714 lifetime_ref.span,
1715 E0261,
1716 "use of undeclared lifetime name `{}`",
1717 lifetime_ref
1718 );
1719 err.span_label(lifetime_ref.span, "undeclared lifetime");
f035d41b 1720 let mut suggests_in_band = false;
6a06907d 1721 let mut suggest_note = true;
74b04a01
XL
1722 for missing in &self.missing_named_lifetime_spots {
1723 match missing {
1724 MissingLifetimeSpot::Generics(generics) => {
5869c6ff
XL
1725 let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
1726 !matches!(
1727 p.kind,
74b04a01
XL
1728 hir::GenericParamKind::Type {
1729 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
1730 ..
5869c6ff 1731 } | hir::GenericParamKind::Lifetime {
6c58768f 1732 kind: hir::LifetimeParamKind::Elided,
5869c6ff
XL
1733 }
1734 )
1735 }) {
74b04a01
XL
1736 (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
1737 } else {
f035d41b 1738 suggests_in_band = true;
74b04a01
XL
1739 (generics.span, format!("<{}>", lifetime_ref))
1740 };
6a06907d
XL
1741 if !span.from_expansion() {
1742 err.span_suggestion(
1743 span,
1744 &format!("consider introducing lifetime `{}` here", lifetime_ref),
1745 sugg,
1746 Applicability::MaybeIncorrect,
1747 );
1748 } else if suggest_note {
1749 suggest_note = false; // Avoid displaying the same help multiple times.
1750 err.span_label(
1751 span,
1752 &format!(
1753 "lifetime `{}` is missing in item created through this procedural \
1754 macro",
1755 lifetime_ref,
1756 ),
1757 );
1758 }
74b04a01
XL
1759 }
1760 MissingLifetimeSpot::HigherRanked { span, span_type } => {
1761 err.span_suggestion(
1762 *span,
1763 &format!(
1764 "consider making the {} lifetime-generic with a new `{}` lifetime",
1765 span_type.descr(),
1766 lifetime_ref
1767 ),
1768 span_type.suggestion(&lifetime_ref.to_string()),
1769 Applicability::MaybeIncorrect,
1770 );
1771 err.note(
1772 "for more information on higher-ranked polymorphism, visit \
6a06907d 1773 https://doc.rust-lang.org/nomicon/hrtb.html",
74b04a01
XL
1774 );
1775 }
3dfed10e 1776 _ => {}
74b04a01
XL
1777 }
1778 }
fc512014 1779 if self.tcx.sess.is_nightly_build()
f035d41b
XL
1780 && !self.tcx.features().in_band_lifetimes
1781 && suggests_in_band
1782 {
1783 err.help(
1784 "if you want to experiment with in-band lifetime bindings, \
6a06907d 1785 add `#![feature(in_band_lifetimes)]` to the crate attributes",
f035d41b
XL
1786 );
1787 }
74b04a01
XL
1788 err.emit();
1789 }
1790
3dfed10e
XL
1791 // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
1792 // generics. We are disallowing this until we can decide on how we want to handle non-'static
1793 // lifetimes in const generics. See issue #74052 for discussion.
1794 crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
1795 let mut err = struct_span_err!(
1796 self.tcx.sess,
1797 lifetime_ref.span,
1798 E0771,
1799 "use of non-static lifetime `{}` in const generic",
1800 lifetime_ref
1801 );
1802 err.note(
1803 "for more information, see issue #74052 \
1804 <https://github.com/rust-lang/rust/issues/74052>",
1805 );
1806 err.emit();
1807 }
1808
74b04a01
XL
1809 crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
1810 if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
1811 if [
1812 self.tcx.lang_items().fn_once_trait(),
1813 self.tcx.lang_items().fn_trait(),
1814 self.tcx.lang_items().fn_mut_trait(),
1815 ]
1816 .contains(&Some(did))
1817 {
1818 let (span, span_type) = match &trait_ref.bound_generic_params {
1819 [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
1820 [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
1821 };
1822 self.missing_named_lifetime_spots
1823 .push(MissingLifetimeSpot::HigherRanked { span, span_type });
1824 return true;
1825 }
1826 };
1827 false
1828 }
1829
1830 crate fn add_missing_lifetime_specifiers_label(
1831 &self,
1832 err: &mut DiagnosticBuilder<'_>,
17df50a5 1833 mut spans_with_counts: Vec<(Span, usize)>,
3dfed10e
XL
1834 lifetime_names: &FxHashSet<Symbol>,
1835 lifetime_spans: Vec<Span>,
74b04a01
XL
1836 params: &[ElisionFailureInfo],
1837 ) {
17df50a5
XL
1838 let snippets: Vec<Option<String>> = spans_with_counts
1839 .iter()
1840 .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
1841 .collect();
1842
1843 // Empty generics are marked with a span of "<", but since from now on
1844 // that information is in the snippets it can be removed from the spans.
1845 for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
1846 if snippet.as_deref() == Some("<") {
1847 *span = span.shrink_to_hi();
1848 }
1849 }
f9f354fc 1850
17df50a5
XL
1851 for &(span, count) in &spans_with_counts {
1852 err.span_label(
1853 span,
1854 format!(
1855 "expected {} lifetime parameter{}",
1856 if count == 1 { "named".to_string() } else { count.to_string() },
1857 pluralize!(count),
1858 ),
1859 );
1860 }
3dfed10e 1861
17df50a5
XL
1862 let suggest_existing =
1863 |err: &mut DiagnosticBuilder<'_>,
1864 name: &str,
1865 formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| {
1866 if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
1867 self.missing_named_lifetime_spots.iter().rev().next()
1868 {
1869 // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
1870 // using `'a`, but also introduce the concept of HRLTs by suggesting
1871 // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
1872 let mut introduce_suggestion = vec![];
1873
1874 let a_to_z_repeat_n = |n| {
1875 (b'a'..=b'z').map(move |c| {
1876 let mut s = '\''.to_string();
1877 s.extend(std::iter::repeat(char::from(c)).take(n));
1878 s
1879 })
1880 };
3dfed10e 1881
17df50a5
XL
1882 // If all single char lifetime names are present, we wrap around and double the chars.
1883 let lt_name = (1..)
1884 .flat_map(a_to_z_repeat_n)
1885 .find(|lt| !lifetime_names.contains(&Symbol::intern(&lt)))
1886 .unwrap();
1887 let msg = format!(
1888 "consider making the {} lifetime-generic with a new `{}` lifetime",
1889 span_type.descr(),
1890 lt_name,
1891 );
1892 err.note(
1893 "for more information on higher-ranked polymorphism, visit \
3dfed10e 1894 https://doc.rust-lang.org/nomicon/hrtb.html",
17df50a5
XL
1895 );
1896 let for_sugg = span_type.suggestion(&lt_name);
1897 for param in params {
1898 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
1899 {
1900 if snippet.starts_with('&') && !snippet.starts_with("&'") {
1901 introduce_suggestion
1902 .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
1903 } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
1904 introduce_suggestion
1905 .push((param.span, format!("&{} {}", lt_name, stripped)));
1906 }
1907 }
1908 }
1909 introduce_suggestion.push((*for_span, for_sugg));
1910 for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
1911 if let Some(formatter) = formatter {
1912 introduce_suggestion.push((*span, formatter(&lt_name)));
3dfed10e
XL
1913 }
1914 }
17df50a5
XL
1915 err.multipart_suggestion_with_style(
1916 &msg,
1917 introduce_suggestion,
1918 Applicability::MaybeIncorrect,
1919 SuggestionStyle::ShowAlways,
1920 );
3dfed10e 1921 }
3dfed10e 1922
17df50a5
XL
1923 let spans_suggs: Vec<_> = formatters
1924 .into_iter()
1925 .zip(spans_with_counts.iter())
1926 .filter_map(|(fmt, (span, _))| {
1927 if let Some(formatter) = fmt { Some((formatter, span)) } else { None }
1928 })
1929 .map(|(formatter, span)| (*span, formatter(name)))
1930 .collect();
1931 err.multipart_suggestion_with_style(
1932 &format!(
1933 "consider using the `{}` lifetime",
1934 lifetime_names.iter().next().unwrap()
1935 ),
1936 spans_suggs,
1937 Applicability::MaybeIncorrect,
1938 SuggestionStyle::ShowAlways,
1939 );
1940 };
1941 let suggest_new = |err: &mut DiagnosticBuilder<'_>, suggs: Vec<Option<String>>| {
f9f354fc
XL
1942 for missing in self.missing_named_lifetime_spots.iter().rev() {
1943 let mut introduce_suggestion = vec![];
1944 let msg;
1945 let should_break;
1946 introduce_suggestion.push(match missing {
1947 MissingLifetimeSpot::Generics(generics) => {
3dfed10e
XL
1948 if generics.span == DUMMY_SP {
1949 // Account for malformed generics in the HIR. This shouldn't happen,
1950 // but if we make a mistake elsewhere, mainly by keeping something in
1951 // `missing_named_lifetime_spots` that we shouldn't, like associated
1952 // `const`s or making a mistake in the AST lowering we would provide
1953 // non-sensical suggestions. Guard against that by skipping these.
1954 // (#74264)
1955 continue;
1956 }
f9f354fc
XL
1957 msg = "consider introducing a named lifetime parameter".to_string();
1958 should_break = true;
29967ef6 1959 if let Some(param) = generics.params.iter().find(|p| {
5869c6ff
XL
1960 !matches!(
1961 p.kind,
1962 hir::GenericParamKind::Type {
1963 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
1964 ..
136023e0
XL
1965 } | hir::GenericParamKind::Lifetime {
1966 kind: hir::LifetimeParamKind::Elided
5869c6ff
XL
1967 }
1968 )
f9f354fc
XL
1969 }) {
1970 (param.span.shrink_to_lo(), "'a, ".to_string())
1971 } else {
1972 (generics.span, "<'a>".to_string())
74b04a01
XL
1973 }
1974 }
f9f354fc
XL
1975 MissingLifetimeSpot::HigherRanked { span, span_type } => {
1976 msg = format!(
1977 "consider making the {} lifetime-generic with a new `'a` lifetime",
1978 span_type.descr(),
1979 );
1980 should_break = false;
1981 err.note(
1982 "for more information on higher-ranked polymorphism, visit \
1983 https://doc.rust-lang.org/nomicon/hrtb.html",
1984 );
1985 (*span, span_type.suggestion("'a"))
1986 }
3dfed10e 1987 MissingLifetimeSpot::Static => {
17df50a5
XL
1988 let mut spans_suggs = Vec::new();
1989 for ((span, count), snippet) in
1990 spans_with_counts.iter().copied().zip(snippets.iter())
1991 {
1992 let (span, sugg) = match snippet.as_deref() {
1993 Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
1994 Some("'_") => (span, "'static".to_owned()),
1995 Some(snippet) if !snippet.ends_with('>') => {
1996 if snippet == "" {
1997 (
1998 span,
1999 std::iter::repeat("'static")
2000 .take(count)
2001 .collect::<Vec<_>>()
2002 .join(", "),
2003 )
2004 } else if snippet == "<" || snippet == "(" {
2005 (
2006 span.shrink_to_hi(),
3dfed10e
XL
2007 std::iter::repeat("'static")
2008 .take(count)
2009 .collect::<Vec<_>>()
17df50a5
XL
2010 .join(", "),
2011 )
2012 } else {
2013 (
2014 span.shrink_to_hi(),
2015 format!(
2016 "<{}>",
2017 std::iter::repeat("'static")
2018 .take(count)
2019 .collect::<Vec<_>>()
2020 .join(", "),
2021 ),
2022 )
2023 }
3dfed10e 2024 }
17df50a5
XL
2025 _ => continue,
2026 };
2027 spans_suggs.push((span, sugg.to_string()));
2028 }
2029 err.multipart_suggestion_with_style(
3dfed10e 2030 "consider using the `'static` lifetime",
17df50a5 2031 spans_suggs,
3dfed10e 2032 Applicability::MaybeIncorrect,
17df50a5 2033 SuggestionStyle::ShowAlways,
3dfed10e
XL
2034 );
2035 continue;
2036 }
f9f354fc
XL
2037 });
2038 for param in params {
2039 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
2040 if snippet.starts_with('&') && !snippet.starts_with("&'") {
2041 introduce_suggestion
2042 .push((param.span, format!("&'a {}", &snippet[1..])));
29967ef6
XL
2043 } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
2044 introduce_suggestion.push((param.span, format!("&'a {}", &stripped)));
f9f354fc 2045 }
74b04a01
XL
2046 }
2047 }
17df50a5
XL
2048 for ((span, _), sugg) in spans_with_counts.iter().copied().zip(suggs.iter()) {
2049 if let Some(sugg) = sugg {
2050 introduce_suggestion.push((span, sugg.to_string()));
2051 }
2052 }
2053 err.multipart_suggestion_with_style(
2054 &msg,
2055 introduce_suggestion,
2056 Applicability::MaybeIncorrect,
2057 SuggestionStyle::ShowAlways,
2058 );
f9f354fc
XL
2059 if should_break {
2060 break;
74b04a01 2061 }
f9f354fc
XL
2062 }
2063 };
2064
1b1a35ee 2065 let lifetime_names: Vec<_> = lifetime_names.iter().collect();
17df50a5
XL
2066 match &lifetime_names[..] {
2067 [name] => {
2068 let mut suggs: Vec<Option<Box<dyn Fn(&str) -> String>>> = Vec::new();
2069 for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
2070 {
2071 suggs.push(match snippet.as_deref() {
2072 Some("&") => Some(Box::new(|name| format!("&{} ", name))),
2073 Some("'_") => Some(Box::new(|n| n.to_string())),
2074 Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
2075 Some("<") => Some(Box::new(move |n| {
2076 std::iter::repeat(n).take(count).collect::<Vec<_>>().join(", ")
2077 })),
2078 Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
2079 format!(
2080 "{}<{}>",
2081 snippet,
2082 std::iter::repeat(name.to_string())
2083 .take(count)
2084 .collect::<Vec<_>>()
2085 .join(", ")
2086 )
2087 })),
2088 _ => None,
2089 });
2090 }
2091 suggest_existing(err, &name.as_str()[..], suggs);
f9f354fc 2092 }
17df50a5
XL
2093 [] => {
2094 let mut suggs = Vec::new();
2095 for (snippet, (_, count)) in
2096 snippets.iter().cloned().zip(spans_with_counts.iter().copied())
2097 {
2098 suggs.push(match snippet.as_deref() {
2099 Some("&") => Some("&'a ".to_string()),
2100 Some("'_") => Some("'a".to_string()),
2101 Some("") => {
2102 Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
2103 }
2104 Some("<") => {
2105 Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
2106 }
2107 Some(snippet) => Some(format!(
3dfed10e
XL
2108 "{}<{}>",
2109 snippet,
17df50a5
XL
2110 std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
2111 )),
2112 None => None,
2113 });
3dfed10e 2114 }
17df50a5 2115 suggest_new(err, suggs);
f9f354fc 2116 }
17df50a5 2117 lts if lts.len() > 1 => {
3dfed10e 2118 err.span_note(lifetime_spans, "these named lifetimes are available to use");
17df50a5
XL
2119
2120 let mut spans_suggs: Vec<_> = Vec::new();
2121 for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
2122 match snippet.as_deref() {
2123 Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
2124 Some("&") => spans_suggs.push((span, "&'lifetime ".to_string())),
2125 _ => {}
2126 }
2127 }
2128
2129 if spans_suggs.len() > 0 {
f9f354fc
XL
2130 // This happens when we have `Foo<T>` where we point at the space before `T`,
2131 // but this can be confusing so we give a suggestion with placeholders.
17df50a5 2132 err.multipart_suggestion_with_style(
f9f354fc 2133 "consider using one of the available lifetimes here",
17df50a5 2134 spans_suggs,
f9f354fc 2135 Applicability::HasPlaceholders,
17df50a5 2136 SuggestionStyle::ShowAlways,
f9f354fc 2137 );
74b04a01
XL
2138 }
2139 }
17df50a5 2140 _ => unreachable!(),
74b04a01
XL
2141 }
2142 }
1b1a35ee 2143
5869c6ff
XL
2144 /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
2145 /// This function will emit an error if `const_generics` is not enabled, the body identified by
1b1a35ee
XL
2146 /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
2147 crate fn maybe_emit_forbidden_non_static_lifetime_error(
2148 &self,
2149 body_id: hir::BodyId,
2150 lifetime_ref: &'tcx hir::Lifetime,
2151 ) {
2152 let is_anon_const = matches!(
2153 self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)),
2154 hir::def::DefKind::AnonConst
2155 );
2156 let is_allowed_lifetime = matches!(
2157 lifetime_ref.name,
2158 hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
2159 );
2160
5869c6ff 2161 if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
1b1a35ee
XL
2162 feature_err(
2163 &self.tcx.sess.parse_sess,
2164 sym::const_generics,
2165 lifetime_ref.span,
2166 "a non-static lifetime is not allowed in a `const`",
2167 )
2168 .emit();
2169 }
2170 }
74b04a01 2171}