Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 115b5c5

Browse files
authoredSep 29, 2022
Rollup merge of #102085 - chenyukang:code-refactor, r=cjgillot
Code refactoring smart_resolve_report_errors `smart_resolve_report_errors` https://github.com/rust-lang/rust/blob/4ecfdfac51b159f68fce608792affb34a70e6f73/compiler/rustc_resolve/src/late/diagnostics.rs#L143 is almost 600 lines of code, we should do some code refactoring.
2 parents cfe8ee2 + db0877f commit 115b5c5

File tree

1 file changed

+366
-247
lines changed

1 file changed

+366
-247
lines changed
 

‎compiler/rustc_resolve/src/late/diagnostics.rs

+366-247
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ pub(super) enum LifetimeElisionCandidate {
130130
Missing(MissingLifetime),
131131
}
132132

133+
/// Only used for diagnostics.
134+
struct BaseError {
135+
msg: String,
136+
fallback_label: String,
137+
span: Span,
138+
span_label: Option<(Span, &'static str)>,
139+
could_be_expr: bool,
140+
suggestion: Option<(Span, &'static str, String)>,
141+
}
142+
133143
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
134144
fn def_span(&self, def_id: DefId) -> Option<Span> {
135145
match def_id.krate {
@@ -138,35 +148,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
138148
}
139149
}
140150

141-
/// Handles error reporting for `smart_resolve_path_fragment` function.
142-
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
143-
pub(crate) fn smart_resolve_report_errors(
151+
fn make_base_error(
144152
&mut self,
145153
path: &[Segment],
146154
span: Span,
147155
source: PathSource<'_>,
148156
res: Option<Res>,
149-
) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
150-
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
151-
let ns = source.namespace();
152-
let is_expected = &|res| source.is_expected(res);
153-
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
154-
155-
debug!(?res, ?source);
156-
157+
) -> BaseError {
157158
// Make the base error.
158-
struct BaseError<'a> {
159-
msg: String,
160-
fallback_label: String,
161-
span: Span,
162-
span_label: Option<(Span, &'a str)>,
163-
could_be_expr: bool,
164-
suggestion: Option<(Span, &'a str, String)>,
165-
}
166159
let mut expected = source.descr_expected();
167160
let path_str = Segment::names_to_string(path);
168161
let item_str = path.last().unwrap().ident;
169-
let base_error = if let Some(res) = res {
162+
if let Some(res) = res {
170163
BaseError {
171164
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
172165
fallback_label: format!("not a {expected}"),
@@ -277,8 +270,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
277270
could_be_expr: false,
278271
suggestion,
279272
}
280-
};
273+
}
274+
}
281275

276+
/// Handles error reporting for `smart_resolve_path_fragment` function.
277+
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
278+
pub(crate) fn smart_resolve_report_errors(
279+
&mut self,
280+
path: &[Segment],
281+
span: Span,
282+
source: PathSource<'_>,
283+
res: Option<Res>,
284+
) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
285+
debug!(?res, ?source);
286+
let base_error = self.make_base_error(path, span, source, res);
282287
let code = source.error_code(res.is_some());
283288
let mut err =
284289
self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
@@ -289,41 +294,79 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
289294
err.span_label(span, label);
290295
}
291296

292-
if let Some(sugg) = base_error.suggestion {
293-
err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
297+
if let Some(ref sugg) = base_error.suggestion {
298+
err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
294299
}
295300

296-
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
297-
err.multipart_suggestion(
298-
"you might have meant to write a `struct` literal",
299-
vec![
300-
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
301-
(span.shrink_to_hi(), "}".to_string()),
302-
],
303-
Applicability::HasPlaceholders,
304-
);
301+
self.suggest_bare_struct_literal(&mut err);
302+
self.suggest_pattern_match_with_let(&mut err, source, span);
303+
304+
self.suggest_self_or_self_ref(&mut err, path, span);
305+
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
306+
if self.suggest_self_ty(&mut err, source, path, span)
307+
|| self.suggest_self_value(&mut err, source, path, span)
308+
{
309+
return (err, Vec::new());
305310
}
306-
match (source, self.diagnostic_metadata.in_if_condition) {
307-
(
308-
PathSource::Expr(_),
309-
Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
310-
) => {
311-
// Icky heuristic so we don't suggest:
312-
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
313-
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
314-
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
315-
err.span_suggestion_verbose(
316-
expr_span.shrink_to_lo(),
317-
"you might have meant to use pattern matching",
318-
"let ",
319-
Applicability::MaybeIncorrect,
320-
);
311+
312+
let (found, candidates) =
313+
self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
314+
if found {
315+
return (err, candidates);
316+
}
317+
318+
if !self.type_ascription_suggestion(&mut err, base_error.span) {
319+
let mut fallback =
320+
self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
321+
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
322+
if fallback {
323+
// Fallback label.
324+
err.span_label(base_error.span, &base_error.fallback_label);
325+
}
326+
}
327+
self.err_code_special_cases(&mut err, source, path, span);
328+
329+
(err, candidates)
330+
}
331+
332+
fn detect_assoct_type_constraint_meant_as_path(
333+
&self,
334+
err: &mut Diagnostic,
335+
base_error: &BaseError,
336+
) {
337+
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
338+
let TyKind::Path(_, path) = &ty.kind else { return; };
339+
for segment in &path.segments {
340+
let Some(params) = &segment.args else { continue; };
341+
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
342+
for param in &params.args {
343+
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
344+
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
345+
continue;
346+
};
347+
for bound in bounds {
348+
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
349+
= bound else
350+
{
351+
continue;
352+
};
353+
if base_error.span == trait_ref.span {
354+
err.span_suggestion_verbose(
355+
constraint.ident.span.between(trait_ref.span),
356+
"you might have meant to write a path instead of an associated type bound",
357+
"::",
358+
Applicability::MachineApplicable,
359+
);
360+
}
321361
}
322362
}
323-
_ => {}
324363
}
364+
}
325365

366+
fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) {
326367
let is_assoc_fn = self.self_type_is_available();
368+
let Some(path_last_segment) = path.last() else { return };
369+
let item_str = path_last_segment.ident;
327370
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
328371
if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
329372
err.span_suggestion_short(
@@ -358,96 +401,25 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
358401
}
359402
}
360403
}
404+
}
361405

362-
self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err);
363-
364-
// Emit special messages for unresolved `Self` and `self`.
365-
if is_self_type(path, ns) {
366-
err.code(rustc_errors::error_code!(E0411));
367-
err.span_label(
368-
span,
369-
"`Self` is only available in impls, traits, and type definitions".to_string(),
370-
);
371-
if let Some(item_kind) = self.diagnostic_metadata.current_item {
372-
err.span_label(
373-
item_kind.ident.span,
374-
format!(
375-
"`Self` not allowed in {} {}",
376-
item_kind.kind.article(),
377-
item_kind.kind.descr()
378-
),
379-
);
380-
}
381-
return (err, Vec::new());
382-
}
383-
if is_self_value(path, ns) {
384-
debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
385-
386-
err.code(rustc_errors::error_code!(E0424));
387-
err.span_label(span, match source {
388-
PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed",
389-
_ => "`self` value is a keyword only available in methods with a `self` parameter",
390-
});
391-
if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
392-
// The current function has a `self' parameter, but we were unable to resolve
393-
// a reference to `self`. This can only happen if the `self` identifier we
394-
// are resolving came from a different hygiene context.
395-
if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
396-
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
397-
} else {
398-
let doesnt = if is_assoc_fn {
399-
let (span, sugg) = fn_kind
400-
.decl()
401-
.inputs
402-
.get(0)
403-
.map(|p| (p.span.shrink_to_lo(), "&self, "))
404-
.unwrap_or_else(|| {
405-
// Try to look for the "(" after the function name, if possible.
406-
// This avoids placing the suggestion into the visibility specifier.
407-
let span = fn_kind
408-
.ident()
409-
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
410-
(
411-
self.r
412-
.session
413-
.source_map()
414-
.span_through_char(span, '(')
415-
.shrink_to_hi(),
416-
"&self",
417-
)
418-
});
419-
err.span_suggestion_verbose(
420-
span,
421-
"add a `self` receiver parameter to make the associated `fn` a method",
422-
sugg,
423-
Applicability::MaybeIncorrect,
424-
);
425-
"doesn't"
426-
} else {
427-
"can't"
428-
};
429-
if let Some(ident) = fn_kind.ident() {
430-
err.span_label(
431-
ident.span,
432-
&format!("this function {} have a `self` parameter", doesnt),
433-
);
434-
}
435-
}
436-
} else if let Some(item_kind) = self.diagnostic_metadata.current_item {
437-
err.span_label(
438-
item_kind.ident.span,
439-
format!(
440-
"`self` not allowed in {} {}",
441-
item_kind.kind.article(),
442-
item_kind.kind.descr()
443-
),
444-
);
445-
}
446-
return (err, Vec::new());
447-
}
448-
406+
fn try_lookup_name_relaxed(
407+
&mut self,
408+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
409+
source: PathSource<'_>,
410+
path: &[Segment],
411+
span: Span,
412+
res: Option<Res>,
413+
base_error: &BaseError,
414+
) -> (bool, Vec<ImportSuggestion>) {
449415
// Try to lookup name in more relaxed fashion for better error reporting.
450416
let ident = path.last().unwrap().ident;
417+
let is_expected = &|res| source.is_expected(res);
418+
let ns = source.namespace();
419+
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
420+
let path_str = Segment::names_to_string(path);
421+
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
422+
451423
let mut candidates = self
452424
.r
453425
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
@@ -494,7 +466,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
494466
{
495467
// Already reported this issue on the lhs of the type ascription.
496468
err.delay_as_bug();
497-
return (err, candidates);
469+
return (true, candidates);
498470
}
499471
}
500472

@@ -522,8 +494,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
522494
);
523495
}
524496
}
497+
525498
// Try Levenshtein algorithm.
526-
let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
499+
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
527500
if path.len() == 1 && self.self_type_is_available() {
528501
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
529502
let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -560,8 +533,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
560533
);
561534
}
562535
}
563-
self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
564-
return (err, candidates);
536+
self.r.add_typo_suggestion(err, typo_sugg, ident_span);
537+
return (true, candidates);
565538
}
566539

567540
// If the first argument in call is `self` suggest calling a method.
@@ -579,121 +552,150 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
579552
format!("self.{path_str}({args_snippet})"),
580553
Applicability::MachineApplicable,
581554
);
582-
return (err, candidates);
555+
return (true, candidates);
583556
}
584557
}
585558

586559
// Try context-dependent help if relaxed lookup didn't work.
587560
if let Some(res) = res {
588561
if self.smart_resolve_context_dependent_help(
589-
&mut err,
562+
err,
590563
span,
591564
source,
592565
res,
593566
&path_str,
594567
&base_error.fallback_label,
595568
) {
596569
// We do this to avoid losing a secondary span when we override the main error span.
597-
self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
598-
return (err, candidates);
570+
self.r.add_typo_suggestion(err, typo_sugg, ident_span);
571+
return (true, candidates);
599572
}
600573
}
574+
return (false, candidates);
575+
}
601576

577+
fn suggest_trait_and_bounds(
578+
&mut self,
579+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
580+
source: PathSource<'_>,
581+
res: Option<Res>,
582+
span: Span,
583+
base_error: &BaseError,
584+
) -> bool {
602585
let is_macro =
603586
base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
604-
if !self.type_ascription_suggestion(&mut err, base_error.span) {
605-
let mut fallback = false;
606-
if let (
607-
PathSource::Trait(AliasPossibility::Maybe),
608-
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
609-
false,
610-
) = (source, res, is_macro)
611-
{
612-
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
613-
fallback = true;
614-
let spans: Vec<Span> = bounds
615-
.iter()
616-
.map(|bound| bound.span())
617-
.filter(|&sp| sp != base_error.span)
618-
.collect();
587+
let mut fallback = false;
619588

620-
let start_span = bounds[0].span();
621-
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
622-
let end_span = bounds.last().unwrap().span();
623-
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
624-
let last_bound_span = spans.last().cloned().unwrap();
625-
let mut multi_span: MultiSpan = spans.clone().into();
626-
for sp in spans {
627-
let msg = if sp == last_bound_span {
628-
format!(
629-
"...because of {these} bound{s}",
630-
these = pluralize!("this", bounds.len() - 1),
631-
s = pluralize!(bounds.len() - 1),
632-
)
633-
} else {
634-
String::new()
635-
};
636-
multi_span.push_span_label(sp, msg);
637-
}
638-
multi_span
639-
.push_span_label(base_error.span, "expected this type to be a trait...");
640-
err.span_help(
641-
multi_span,
642-
"`+` is used to constrain a \"trait object\" type with lifetimes or \
643-
auto-traits; structs and enums can't be bound in that way",
644-
);
645-
if bounds.iter().all(|bound| match bound {
646-
ast::GenericBound::Outlives(_) => true,
647-
ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
648-
}) {
649-
let mut sugg = vec![];
650-
if base_error.span != start_span {
651-
sugg.push((start_span.until(base_error.span), String::new()));
652-
}
653-
if base_error.span != end_span {
654-
sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
655-
}
589+
if let (
590+
PathSource::Trait(AliasPossibility::Maybe),
591+
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
592+
false,
593+
) = (source, res, is_macro)
594+
{
595+
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
596+
fallback = true;
597+
let spans: Vec<Span> = bounds
598+
.iter()
599+
.map(|bound| bound.span())
600+
.filter(|&sp| sp != base_error.span)
601+
.collect();
656602

657-
err.multipart_suggestion(
658-
"if you meant to use a type and not a trait here, remove the bounds",
659-
sugg,
660-
Applicability::MaybeIncorrect,
661-
);
603+
let start_span = bounds[0].span();
604+
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
605+
let end_span = bounds.last().unwrap().span();
606+
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
607+
let last_bound_span = spans.last().cloned().unwrap();
608+
let mut multi_span: MultiSpan = spans.clone().into();
609+
for sp in spans {
610+
let msg = if sp == last_bound_span {
611+
format!(
612+
"...because of {these} bound{s}",
613+
these = pluralize!("this", bounds.len() - 1),
614+
s = pluralize!(bounds.len() - 1),
615+
)
616+
} else {
617+
String::new()
618+
};
619+
multi_span.push_span_label(sp, msg);
620+
}
621+
multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
622+
err.span_help(
623+
multi_span,
624+
"`+` is used to constrain a \"trait object\" type with lifetimes or \
625+
auto-traits; structs and enums can't be bound in that way",
626+
);
627+
if bounds.iter().all(|bound| match bound {
628+
ast::GenericBound::Outlives(_) => true,
629+
ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
630+
}) {
631+
let mut sugg = vec![];
632+
if base_error.span != start_span {
633+
sugg.push((start_span.until(base_error.span), String::new()));
662634
}
635+
if base_error.span != end_span {
636+
sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
637+
}
638+
639+
err.multipart_suggestion(
640+
"if you meant to use a type and not a trait here, remove the bounds",
641+
sugg,
642+
Applicability::MaybeIncorrect,
643+
);
663644
}
664645
}
646+
}
665647

666-
fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
648+
fallback |= self.restrict_assoc_type_in_where_clause(span, err);
649+
fallback
650+
}
667651

668-
if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
669-
fallback = true;
670-
match self.diagnostic_metadata.current_let_binding {
671-
Some((pat_sp, Some(ty_sp), None))
672-
if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
673-
{
674-
err.span_suggestion_short(
675-
pat_sp.between(ty_sp),
676-
"use `=` if you meant to assign",
677-
" = ",
678-
Applicability::MaybeIncorrect,
679-
);
680-
}
681-
_ => {}
652+
fn suggest_typo(
653+
&mut self,
654+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
655+
source: PathSource<'_>,
656+
path: &[Segment],
657+
span: Span,
658+
base_error: &BaseError,
659+
) -> bool {
660+
let is_expected = &|res| source.is_expected(res);
661+
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
662+
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
663+
let mut fallback = false;
664+
if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
665+
fallback = true;
666+
match self.diagnostic_metadata.current_let_binding {
667+
Some((pat_sp, Some(ty_sp), None))
668+
if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
669+
{
670+
err.span_suggestion_short(
671+
pat_sp.between(ty_sp),
672+
"use `=` if you meant to assign",
673+
" = ",
674+
Applicability::MaybeIncorrect,
675+
);
682676
}
683-
684-
// If the trait has a single item (which wasn't matched by Levenshtein), suggest it
685-
let suggestion = self.get_single_associated_item(&path, &source, is_expected);
686-
self.r.add_typo_suggestion(&mut err, suggestion, ident_span);
687-
}
688-
if fallback {
689-
// Fallback label.
690-
err.span_label(base_error.span, base_error.fallback_label);
677+
_ => {}
691678
}
679+
680+
// If the trait has a single item (which wasn't matched by Levenshtein), suggest it
681+
let suggestion = self.get_single_associated_item(&path, &source, is_expected);
682+
self.r.add_typo_suggestion(err, suggestion, ident_span);
692683
}
684+
fallback
685+
}
686+
687+
fn err_code_special_cases(
688+
&mut self,
689+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
690+
source: PathSource<'_>,
691+
path: &[Segment],
692+
span: Span,
693+
) {
693694
if let Some(err_code) = &err.code {
694695
if err_code == &rustc_errors::error_code!(E0425) {
695696
for label_rib in &self.label_ribs {
696697
for (label_ident, node_id) in &label_rib.bindings {
698+
let ident = path.last().unwrap().ident;
697699
if format!("'{}", ident) == label_ident.to_string() {
698700
err.span_label(label_ident.span, "a label with a similar name exists");
699701
if let PathSource::Expr(Some(Expr {
@@ -724,38 +726,116 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
724726
}
725727
}
726728
}
729+
}
727730

728-
(err, candidates)
731+
/// Emit special messages for unresolved `Self` and `self`.
732+
fn suggest_self_ty(
733+
&mut self,
734+
err: &mut Diagnostic,
735+
source: PathSource<'_>,
736+
path: &[Segment],
737+
span: Span,
738+
) -> bool {
739+
if !is_self_type(path, source.namespace()) {
740+
return false;
741+
}
742+
err.code(rustc_errors::error_code!(E0411));
743+
err.span_label(
744+
span,
745+
"`Self` is only available in impls, traits, and type definitions".to_string(),
746+
);
747+
if let Some(item_kind) = self.diagnostic_metadata.current_item {
748+
err.span_label(
749+
item_kind.ident.span,
750+
format!(
751+
"`Self` not allowed in {} {}",
752+
item_kind.kind.article(),
753+
item_kind.kind.descr()
754+
),
755+
);
756+
}
757+
true
729758
}
730759

731-
fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
732-
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
733-
let TyKind::Path(_, path) = &ty.kind else { return; };
734-
for segment in &path.segments {
735-
let Some(params) = &segment.args else { continue; };
736-
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
737-
for param in &params.args {
738-
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
739-
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
740-
continue;
760+
fn suggest_self_value(
761+
&mut self,
762+
err: &mut Diagnostic,
763+
source: PathSource<'_>,
764+
path: &[Segment],
765+
span: Span,
766+
) -> bool {
767+
if !is_self_value(path, source.namespace()) {
768+
return false;
769+
}
770+
771+
debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
772+
err.code(rustc_errors::error_code!(E0424));
773+
err.span_label(
774+
span,
775+
match source {
776+
PathSource::Pat => {
777+
"`self` value is a keyword and may not be bound to variables or shadowed"
778+
}
779+
_ => "`self` value is a keyword only available in methods with a `self` parameter",
780+
},
781+
);
782+
let is_assoc_fn = self.self_type_is_available();
783+
if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
784+
// The current function has a `self' parameter, but we were unable to resolve
785+
// a reference to `self`. This can only happen if the `self` identifier we
786+
// are resolving came from a different hygiene context.
787+
if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
788+
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
789+
} else {
790+
let doesnt = if is_assoc_fn {
791+
let (span, sugg) = fn_kind
792+
.decl()
793+
.inputs
794+
.get(0)
795+
.map(|p| (p.span.shrink_to_lo(), "&self, "))
796+
.unwrap_or_else(|| {
797+
// Try to look for the "(" after the function name, if possible.
798+
// This avoids placing the suggestion into the visibility specifier.
799+
let span = fn_kind
800+
.ident()
801+
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
802+
(
803+
self.r
804+
.session
805+
.source_map()
806+
.span_through_char(span, '(')
807+
.shrink_to_hi(),
808+
"&self",
809+
)
810+
});
811+
err.span_suggestion_verbose(
812+
span,
813+
"add a `self` receiver parameter to make the associated `fn` a method",
814+
sugg,
815+
Applicability::MaybeIncorrect,
816+
);
817+
"doesn't"
818+
} else {
819+
"can't"
741820
};
742-
for bound in bounds {
743-
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
744-
= bound else
745-
{
746-
continue;
747-
};
748-
if base_span == trait_ref.span {
749-
err.span_suggestion_verbose(
750-
constraint.ident.span.between(trait_ref.span),
751-
"you might have meant to write a path instead of an associated type bound",
752-
"::",
753-
Applicability::MachineApplicable,
754-
);
755-
}
821+
if let Some(ident) = fn_kind.ident() {
822+
err.span_label(
823+
ident.span,
824+
&format!("this function {} have a `self` parameter", doesnt),
825+
);
756826
}
757827
}
828+
} else if let Some(item_kind) = self.diagnostic_metadata.current_item {
829+
err.span_label(
830+
item_kind.ident.span,
831+
format!(
832+
"`self` not allowed in {} {}",
833+
item_kind.kind.article(),
834+
item_kind.kind.descr()
835+
),
836+
);
758837
}
838+
true
759839
}
760840

761841
fn suggest_swapping_misplaced_self_ty_and_trait(
@@ -787,6 +867,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
787867
}
788868
}
789869

870+
fn suggest_bare_struct_literal(&mut self, err: &mut Diagnostic) {
871+
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
872+
err.multipart_suggestion(
873+
"you might have meant to write a `struct` literal",
874+
vec![
875+
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
876+
(span.shrink_to_hi(), "}".to_string()),
877+
],
878+
Applicability::HasPlaceholders,
879+
);
880+
}
881+
}
882+
883+
fn suggest_pattern_match_with_let(
884+
&mut self,
885+
err: &mut Diagnostic,
886+
source: PathSource<'_>,
887+
span: Span,
888+
) {
889+
if let PathSource::Expr(_) = source &&
890+
let Some(Expr {
891+
span: expr_span,
892+
kind: ExprKind::Assign(lhs, _, _),
893+
..
894+
}) = self.diagnostic_metadata.in_if_condition {
895+
// Icky heuristic so we don't suggest:
896+
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
897+
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
898+
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
899+
err.span_suggestion_verbose(
900+
expr_span.shrink_to_lo(),
901+
"you might have meant to use pattern matching",
902+
"let ",
903+
Applicability::MaybeIncorrect,
904+
);
905+
}
906+
}
907+
}
908+
790909
fn get_single_associated_item(
791910
&mut self,
792911
path: &[Segment],

0 commit comments

Comments
 (0)
Please sign in to comment.