@@ -9,8 +9,85 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa
9
9
use super :: HirTyLowerer ;
10
10
11
11
impl < ' 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
+
12
89
/// 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 > (
14
91
& self ,
15
92
self_ty : & hir:: Ty < ' _ > ,
16
93
diag : & mut Diag < ' _ , G > ,
@@ -75,9 +152,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
75
152
}
76
153
77
154
/// 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 {
79
156
let tcx = self . tcx ( ) ;
80
157
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>`.
81
160
let ( sig, generics, owner) = match tcx. hir_node_by_def_id ( parent_id) {
82
161
hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Fn ( sig, generics, _) , .. } ) => {
83
162
( sig, generics, None )
@@ -186,71 +265,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
186
265
false
187
266
}
188
267
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 ) ;
212
270
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 ;
222
280
}
223
281
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
241
284
} 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 ;
253
291
}
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
+ ) ;
254
299
}
255
300
}
256
301
}
0 commit comments