1
1
use rustc_data_structures:: fx:: FxIndexSet ;
2
+ use rustc_data_structures:: unord:: UnordSet ;
2
3
use rustc_errors:: { Applicability , LintDiagnostic } ;
3
4
use rustc_hir as hir;
4
5
use rustc_hir:: def:: DefKind ;
5
6
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
6
7
use rustc_hir:: intravisit;
8
+ use rustc_macros:: LintDiagnostic ;
9
+ use rustc_middle:: middle:: resolve_bound_vars:: ResolvedArg ;
7
10
use rustc_middle:: ty:: {
8
11
self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
9
12
} ;
@@ -14,21 +17,30 @@ use rustc_span::{BytePos, Span};
14
17
use crate :: fluent_generated as fluent;
15
18
use crate :: { LateContext , LateLintPass } ;
16
19
20
+ // TODO: feature gate these too
21
+
17
22
declare_lint ! {
18
23
/// UwU
19
24
pub IMPL_TRAIT_OVERCAPTURES ,
20
- Warn ,
25
+ Allow ,
21
26
"will capture more lifetimes than possibly intended in edition 2024" ,
22
27
@future_incompatible = FutureIncompatibleInfo {
23
28
reason: FutureIncompatibilityReason :: EditionSemanticsChange ( Edition :: Edition2024 ) ,
24
29
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>" ,
25
30
} ;
26
31
}
27
32
33
+ declare_lint ! {
34
+ /// UwU
35
+ pub IMPL_TRAIT_REDUNDANT_CAPTURES ,
36
+ Warn ,
37
+ "uwu 2"
38
+ }
39
+
28
40
declare_lint_pass ! (
29
41
/// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
30
42
/// in edition 2024.
31
- ImplTraitOvercaptures => [ IMPL_TRAIT_OVERCAPTURES ]
43
+ ImplTraitOvercaptures => [ IMPL_TRAIT_OVERCAPTURES , IMPL_TRAIT_REDUNDANT_CAPTURES ]
32
44
) ;
33
45
34
46
impl < ' tcx > LateLintPass < ' tcx > for ImplTraitOvercaptures {
@@ -109,14 +121,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
109
121
let unique = self . in_scope_parameters . insert ( def_id) ;
110
122
assert ! ( unique) ;
111
123
}
112
- ty:: BoundVariableKind :: Ty ( _) => {
113
- todo ! ( "we don't support late-bound type params in `impl Trait`" )
114
- }
115
- ty:: BoundVariableKind :: Region ( ..) => {
116
- unreachable ! ( "all AST-derived bound regions should have a name" )
117
- }
118
- ty:: BoundVariableKind :: Const => {
119
- unreachable ! ( "non-lifetime binder consts are not allowed" )
124
+ _ => {
125
+ self . tcx . dcx ( ) . span_delayed_bug (
126
+ self . tcx . def_span ( self . parent_def_id ) ,
127
+ format ! ( "unsupported bound variable kind: {arg:?}" ) ,
128
+ ) ;
120
129
}
121
130
}
122
131
}
@@ -144,8 +153,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
144
153
self . tcx . hir_node_by_def_id ( opaque_def_id) . expect_item ( ) . expect_opaque_ty ( )
145
154
&& let hir:: OpaqueTyOrigin :: FnReturn ( parent_def_id) = opaque. origin
146
155
&& parent_def_id == self . parent_def_id
147
- // And if the opaque doesn't already have `use<>` syntax on it...
148
- && opaque. precise_capturing_args . is_none ( )
149
156
{
150
157
// Compute the set of args that are captured by the opaque...
151
158
let mut captured = FxIndexSet :: default ( ) ;
@@ -178,9 +185,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
178
185
. map ( |def_id| self . tcx . def_span ( def_id) )
179
186
. collect ( ) ;
180
187
181
- if !uncaptured_spans. is_empty ( ) {
182
- let opaque_span = self . tcx . def_span ( opaque_def_id) ;
188
+ let opaque_span = self . tcx . def_span ( opaque_def_id) ;
189
+ let new_capture_rules =
190
+ opaque_span. at_least_rust_2024 ( ) || self . tcx . features ( ) . lifetime_capture_rules_2024 ;
183
191
192
+ // If we have uncaptured args, and if the opaque doesn't already have
193
+ // `use<>` syntax on it, and we're < edition 2024, then warn the user.
194
+ if !new_capture_rules
195
+ && opaque. precise_capturing_args . is_none ( )
196
+ && !uncaptured_spans. is_empty ( )
197
+ {
184
198
let suggestion = if let Ok ( snippet) =
185
199
self . tcx . sess . source_map ( ) . span_to_snippet ( opaque_span)
186
200
&& snippet. starts_with ( "impl " )
@@ -207,18 +221,72 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
207
221
None
208
222
} ;
209
223
210
- self . tcx . emit_node_lint (
224
+ self . tcx . emit_node_span_lint (
211
225
IMPL_TRAIT_OVERCAPTURES ,
212
226
self . tcx . local_def_id_to_hir_id ( opaque_def_id) ,
227
+ opaque_span,
213
228
ImplTraitOvercapturesLint {
214
- opaque_span,
215
229
self_ty : t,
216
230
num_captured : uncaptured_spans. len ( ) ,
217
231
uncaptured_spans,
218
232
suggestion,
219
233
} ,
220
234
) ;
221
235
}
236
+ // Otherwise, if we are edition 2024, have `use<>` syntax, and
237
+ // have no uncaptured args, then we should warn to the user that
238
+ // it's redundant to capture all args explicitly.
239
+ else if new_capture_rules
240
+ && let Some ( ( captured_args, capturing_span) ) = opaque. precise_capturing_args
241
+ {
242
+ let mut explicitly_captured = UnordSet :: default ( ) ;
243
+ for arg in captured_args {
244
+ match self . tcx . named_bound_var ( arg. hir_id ( ) ) {
245
+ Some (
246
+ ResolvedArg :: EarlyBound ( def_id) | ResolvedArg :: LateBound ( _, _, def_id) ,
247
+ ) => {
248
+ if self . tcx . def_kind ( self . tcx . parent ( def_id) ) == DefKind :: OpaqueTy {
249
+ let ( ty:: ReEarlyParam ( ty:: EarlyParamRegion { def_id, .. } )
250
+ | ty:: ReLateParam ( ty:: LateParamRegion {
251
+ bound_region : ty:: BoundRegionKind :: BrNamed ( def_id, _) ,
252
+ ..
253
+ } ) ) = self
254
+ . tcx
255
+ . map_opaque_lifetime_to_parent_lifetime ( def_id. expect_local ( ) )
256
+ . kind ( )
257
+ else {
258
+ span_bug ! (
259
+ self . tcx. def_span( def_id) ,
260
+ "variable should have been duplicated from a parent"
261
+ ) ;
262
+ } ;
263
+ explicitly_captured. insert ( def_id) ;
264
+ } else {
265
+ explicitly_captured. insert ( def_id) ;
266
+ }
267
+ }
268
+ _ => {
269
+ self . tcx . dcx ( ) . span_delayed_bug (
270
+ self . tcx ( ) . hir ( ) . span ( arg. hir_id ( ) ) ,
271
+ "no valid for captured arg" ,
272
+ ) ;
273
+ }
274
+ }
275
+ }
276
+
277
+ if self
278
+ . in_scope_parameters
279
+ . iter ( )
280
+ . all ( |def_id| explicitly_captured. contains ( def_id) )
281
+ {
282
+ self . tcx . emit_node_span_lint (
283
+ IMPL_TRAIT_REDUNDANT_CAPTURES ,
284
+ self . tcx . local_def_id_to_hir_id ( opaque_def_id) ,
285
+ opaque_span,
286
+ ImplTraitRedundantCapturesLint { capturing_span } ,
287
+ ) ;
288
+ }
289
+ }
222
290
223
291
// Walk into the bounds of the opaque, too, since we want to get nested opaques
224
292
// in this lint as well. Interestingly, one place that I expect this lint to fire
@@ -236,7 +304,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
236
304
}
237
305
238
306
struct ImplTraitOvercapturesLint < ' tcx > {
239
- opaque_span : Span ,
240
307
uncaptured_spans : Vec < Span > ,
241
308
self_ty : Ty < ' tcx > ,
242
309
num_captured : usize ,
@@ -247,7 +314,6 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
247
314
fn decorate_lint < ' b > ( self , diag : & ' b mut rustc_errors:: Diag < ' a , ( ) > ) {
248
315
diag. arg ( "self_ty" , self . self_ty . to_string ( ) )
249
316
. arg ( "num_captured" , self . num_captured )
250
- . span ( self . opaque_span )
251
317
. span_note ( self . uncaptured_spans , fluent:: lint_note)
252
318
. note ( fluent:: lint_note2) ;
253
319
if let Some ( ( suggestion, span) ) = self . suggestion {
@@ -265,6 +331,13 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
265
331
}
266
332
}
267
333
334
+ #[ derive( LintDiagnostic ) ]
335
+ #[ diag( lint_impl_trait_redundant_captures) ]
336
+ struct ImplTraitRedundantCapturesLint {
337
+ #[ suggestion( lint_suggestion, code = "" , applicability = "machine-applicable" ) ]
338
+ capturing_span : Span ,
339
+ }
340
+
268
341
fn extract_def_id_from_arg < ' tcx > (
269
342
tcx : TyCtxt < ' tcx > ,
270
343
generics : & ' tcx ty:: Generics ,
0 commit comments