]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_hir_analysis/src/astconv/lint.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / astconv / lint.rs
1 use rustc_ast::TraitObjectSyntax;
2 use rustc_errors::{Diagnostic, StashKey};
3 use rustc_hir as hir;
4 use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
5 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
6
7 use super::AstConv;
8
9 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10 /// Make sure that we are in the condition to suggest the blanket implementation.
11 pub(super) fn maybe_lint_blanket_trait_impl(
12 &self,
13 self_ty: &hir::Ty<'_>,
14 diag: &mut Diagnostic,
15 ) {
16 let tcx = self.tcx();
17 let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
18 if let hir::Node::Item(hir::Item {
19 kind:
20 hir::ItemKind::Impl(hir::Impl {
21 self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
22 }),
23 ..
24 }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
25 {
26 if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
27 return;
28 }
29 let of_trait_span = of_trait_ref.path.span;
30 // make sure that we are not calling unwrap to abort during the compilation
31 let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
32 let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
33 // check if the trait has generics, to make a correct suggestion
34 let param_name = generics.params.next_type_param_name(None);
35
36 let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
37 (span, format!(", {param_name}: {impl_trait_name}"))
38 } else {
39 (generics.span, format!("<{param_name}: {impl_trait_name}>"))
40 };
41 diag.multipart_suggestion(
42 format!("alternatively use a blanket \
43 implementation to implement `{of_trait_name}` for \
44 all types that also implement `{impl_trait_name}`"),
45 vec![
46 (self_ty.span, param_name),
47 add_generic_sugg,
48 ],
49 Applicability::MaybeIncorrect,
50 );
51 }
52 }
53
54 pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
55 let tcx = self.tcx();
56 if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
57 self_ty.kind
58 {
59 let needs_bracket = in_path
60 && !tcx
61 .sess
62 .source_map()
63 .span_to_prev_source(self_ty.span)
64 .ok()
65 .is_some_and(|s| s.trim_end().ends_with('<'));
66
67 let is_global = poly_trait_ref.trait_ref.path.is_global();
68
69 let mut sugg = Vec::from_iter([(
70 self_ty.span.shrink_to_lo(),
71 format!(
72 "{}dyn {}",
73 if needs_bracket { "<" } else { "" },
74 if is_global { "(" } else { "" },
75 ),
76 )]);
77
78 if is_global || needs_bracket {
79 sugg.push((
80 self_ty.span.shrink_to_hi(),
81 format!(
82 "{}{}",
83 if is_global { ")" } else { "" },
84 if needs_bracket { ">" } else { "" },
85 ),
86 ));
87 }
88
89 if self_ty.span.edition().at_least_rust_2021() {
90 let msg = "trait objects must include the `dyn` keyword";
91 let label = "add `dyn` keyword before this trait";
92 let mut diag =
93 rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
94 if self_ty.span.can_be_used_for_suggestions() {
95 diag.multipart_suggestion_verbose(
96 label,
97 sugg,
98 Applicability::MachineApplicable,
99 );
100 }
101 // check if the impl trait that we are considering is a impl of a local trait
102 self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
103 diag.stash(self_ty.span, StashKey::TraitMissingMethod);
104 } else {
105 let msg = "trait objects without an explicit `dyn` are deprecated";
106 tcx.struct_span_lint_hir(
107 BARE_TRAIT_OBJECTS,
108 self_ty.hir_id,
109 self_ty.span,
110 msg,
111 |lint| {
112 lint.multipart_suggestion_verbose(
113 "use `dyn`",
114 sugg,
115 Applicability::MachineApplicable,
116 );
117 self.maybe_lint_blanket_trait_impl(&self_ty, lint);
118 lint
119 },
120 );
121 }
122 }
123 }
124 }