@@ -9,8 +9,85 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa
99use super :: HirTyLowerer ;
1010
1111impl < ' tcx > dyn HirTyLowerer < ' tcx > + ' _ {
12+ /// Prohibit or lint against *bare* trait object types depending on the edition.
13+ ///
14+ /// *Bare* trait object types are ones that aren't preceeded by the keyword `dyn`.
15+ /// In edition 2021 and onward we emit a hard error for them.
16+ pub ( super ) fn prohibit_or_lint_bare_trait_object_ty (
17+ & self ,
18+ self_ty : & hir:: Ty < ' _ > ,
19+ in_path : bool ,
20+ ) {
21+ let tcx = self . tcx ( ) ;
22+
23+ let hir:: TyKind :: TraitObject ( [ poly_trait_ref, ..] , _, TraitObjectSyntax :: None ) =
24+ self_ty. kind
25+ else {
26+ return ;
27+ } ;
28+
29+ let needs_bracket = in_path
30+ && !tcx
31+ . sess
32+ . source_map ( )
33+ . span_to_prev_source ( self_ty. span )
34+ . ok ( )
35+ . is_some_and ( |s| s. trim_end ( ) . ends_with ( '<' ) ) ;
36+
37+ let is_global = poly_trait_ref. trait_ref . path . is_global ( ) ;
38+
39+ let mut sugg = vec ! [ (
40+ self_ty. span. shrink_to_lo( ) ,
41+ format!(
42+ "{}dyn {}" ,
43+ if needs_bracket { "<" } else { "" } ,
44+ if is_global { "(" } else { "" } ,
45+ ) ,
46+ ) ] ;
47+
48+ if is_global || needs_bracket {
49+ sugg. push ( (
50+ self_ty. span . shrink_to_hi ( ) ,
51+ format ! (
52+ "{}{}" ,
53+ if is_global { ")" } else { "" } ,
54+ if needs_bracket { ">" } else { "" } ,
55+ ) ,
56+ ) ) ;
57+ }
58+
59+ if self_ty. span . edition ( ) . at_least_rust_2021 ( ) {
60+ let msg = "trait objects must include the `dyn` keyword" ;
61+ let label = "add `dyn` keyword before this trait" ;
62+ let mut diag =
63+ rustc_errors:: struct_span_code_err!( tcx. dcx( ) , self_ty. span, E0782 , "{}" , msg) ;
64+ if self_ty. span . can_be_used_for_suggestions ( )
65+ && !self . maybe_suggest_impl_trait ( self_ty, & mut diag)
66+ {
67+ // FIXME: Only emit this suggestion if the trait is object safe.
68+ diag. multipart_suggestion_verbose ( label, sugg, Applicability :: MachineApplicable ) ;
69+ }
70+ // Check if the impl trait that we are considering is an impl of a local trait.
71+ self . maybe_suggest_blanket_trait_impl ( self_ty, & mut diag) ;
72+ self . maybe_suggest_assoc_ty_bound ( self_ty, & mut diag) ;
73+ diag. stash ( self_ty. span , StashKey :: TraitMissingMethod ) ;
74+ } else {
75+ let msg = "trait objects without an explicit `dyn` are deprecated" ;
76+ tcx. node_span_lint ( BARE_TRAIT_OBJECTS , self_ty. hir_id , self_ty. span , msg, |lint| {
77+ if self_ty. span . can_be_used_for_suggestions ( ) {
78+ lint. multipart_suggestion_verbose (
79+ "if this is an object-safe trait, use `dyn`" ,
80+ sugg,
81+ Applicability :: MachineApplicable ,
82+ ) ;
83+ }
84+ self . maybe_suggest_blanket_trait_impl ( self_ty, lint) ;
85+ } ) ;
86+ }
87+ }
88+
1289 /// Make sure that we are in the condition to suggest the blanket implementation.
13- pub ( super ) fn maybe_lint_blanket_trait_impl < G : EmissionGuarantee > (
90+ fn maybe_suggest_blanket_trait_impl < G : EmissionGuarantee > (
1491 & self ,
1592 self_ty : & hir:: Ty < ' _ > ,
1693 diag : & mut Diag < ' _ , G > ,
@@ -75,9 +152,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
75152 }
76153
77154 /// Make sure that we are in the condition to suggest `impl Trait`.
78- fn maybe_lint_impl_trait ( & self , self_ty : & hir:: Ty < ' _ > , diag : & mut Diag < ' _ > ) -> bool {
155+ fn maybe_suggest_impl_trait ( & self , self_ty : & hir:: Ty < ' _ > , diag : & mut Diag < ' _ > ) -> bool {
79156 let tcx = self . tcx ( ) ;
80157 let parent_id = tcx. hir ( ) . get_parent_item ( self_ty. hir_id ) . def_id ;
158+ // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
159+ // and suggest `Trait0<Ty = impl Trait1>`.
81160 let ( sig, generics, owner) = match tcx. hir_node_by_def_id ( parent_id) {
82161 hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Fn ( sig, generics, _) , .. } ) => {
83162 ( sig, generics, None )
@@ -186,71 +265,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
186265 false
187266 }
188267
189- pub ( super ) fn maybe_lint_bare_trait ( & self , self_ty : & hir:: Ty < ' _ > , in_path : bool ) {
190- let tcx = self . tcx ( ) ;
191- if let hir:: TyKind :: TraitObject ( [ poly_trait_ref, ..] , _, TraitObjectSyntax :: None ) =
192- self_ty. kind
193- {
194- let needs_bracket = in_path
195- && !tcx
196- . sess
197- . source_map ( )
198- . span_to_prev_source ( self_ty. span )
199- . ok ( )
200- . is_some_and ( |s| s. trim_end ( ) . ends_with ( '<' ) ) ;
201-
202- let is_global = poly_trait_ref. trait_ref . path . is_global ( ) ;
203-
204- let mut sugg = Vec :: from_iter ( [ (
205- self_ty. span . shrink_to_lo ( ) ,
206- format ! (
207- "{}dyn {}" ,
208- if needs_bracket { "<" } else { "" } ,
209- if is_global { "(" } else { "" } ,
210- ) ,
211- ) ] ) ;
268+ fn maybe_suggest_assoc_ty_bound ( & self , self_ty : & hir:: Ty < ' _ > , diag : & mut Diag < ' _ > ) {
269+ let mut parents = self . tcx ( ) . hir ( ) . parent_iter ( self_ty. hir_id ) ;
212270
213- if is_global || needs_bracket {
214- sugg . push ( (
215- self_ty . span . shrink_to_hi ( ) ,
216- format ! (
217- "{}{}" ,
218- if is_global { ")" } else { "" } ,
219- if needs_bracket { ">" } else { "" } ,
220- ) ,
221- ) ) ;
271+ if let Some ( ( _ , hir :: Node :: TypeBinding ( binding ) ) ) = parents . next ( )
272+ && let hir :: TypeBindingKind :: Equality { term : hir :: Term :: Ty ( obj_ty ) } = binding . kind
273+ {
274+ if let Some ( ( _ , hir :: Node :: TraitRef ( .. ) ) ) = parents . next ( )
275+ && let Some ( ( _ , hir :: Node :: Ty ( ty ) ) ) = parents . next ( )
276+ && let hir :: TyKind :: TraitObject ( .. ) = ty . kind
277+ {
278+ // Assoc ty bounds aren't permitted inside trait object types.
279+ return ;
222280 }
223281
224- if self_ty. span . edition ( ) . at_least_rust_2021 ( ) {
225- let msg = "trait objects must include the `dyn` keyword" ;
226- let label = "add `dyn` keyword before this trait" ;
227- let mut diag =
228- rustc_errors:: struct_span_code_err!( tcx. dcx( ) , self_ty. span, E0782 , "{}" , msg) ;
229- if self_ty. span . can_be_used_for_suggestions ( )
230- && !self . maybe_lint_impl_trait ( self_ty, & mut diag)
231- {
232- diag. multipart_suggestion_verbose (
233- label,
234- sugg,
235- Applicability :: MachineApplicable ,
236- ) ;
237- }
238- // check if the impl trait that we are considering is a impl of a local trait
239- self . maybe_lint_blanket_trait_impl ( self_ty, & mut diag) ;
240- diag. stash ( self_ty. span , StashKey :: TraitMissingMethod ) ;
282+ let lo = if binding. gen_args . span_ext . is_dummy ( ) {
283+ binding. ident . span
241284 } else {
242- let msg = "trait objects without an explicit `dyn` are deprecated" ;
243- tcx. node_span_lint ( BARE_TRAIT_OBJECTS , self_ty. hir_id , self_ty. span , msg, |lint| {
244- if self_ty. span . can_be_used_for_suggestions ( ) {
245- lint. multipart_suggestion_verbose (
246- "if this is an object-safe trait, use `dyn`" ,
247- sugg,
248- Applicability :: MachineApplicable ,
249- ) ;
250- }
251- self . maybe_lint_blanket_trait_impl ( self_ty, lint) ;
252- } ) ;
285+ binding. gen_args . span_ext
286+ } ;
287+ let hi = obj_ty. span ;
288+
289+ if !lo. eq_ctxt ( hi) {
290+ return ;
253291 }
292+
293+ diag. span_suggestion_verbose (
294+ lo. between ( hi) ,
295+ "you might have meant to write a bound here" ,
296+ ": " ,
297+ Applicability :: MaybeIncorrect ,
298+ ) ;
254299 }
255300 }
256301}
0 commit comments