@@ -2,19 +2,11 @@ use rustc_errors::MultiSpan;
2
2
use rustc_hir:: def:: DefKind ;
3
3
use rustc_hir:: intravisit:: { self , Visitor } ;
4
4
use rustc_hir:: { Body , HirId , Item , ItemKind , Node , Path , QPath , TyKind } ;
5
- use rustc_infer:: infer:: InferCtxt ;
6
- use rustc_infer:: traits:: { Obligation , ObligationCause } ;
7
- use rustc_middle:: ty:: {
8
- self , Binder , EarlyBinder , TraitRef , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeSuperFoldable ,
9
- } ;
5
+ use rustc_middle:: ty:: TyCtxt ;
10
6
use rustc_session:: { declare_lint, impl_lint_pass} ;
11
7
use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
12
8
use rustc_span:: symbol:: kw;
13
- use rustc_span:: { ExpnKind , MacroKind , Span , Symbol , sym} ;
14
- use rustc_trait_selection:: error_reporting:: traits:: ambiguity:: {
15
- CandidateSource , compute_applicable_impls_for_diagnostics,
16
- } ;
17
- use rustc_trait_selection:: infer:: TyCtxtInferExt ;
9
+ use rustc_span:: { ExpnKind , MacroKind , Span , Symbol , sym, sym} ;
18
10
19
11
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
20
12
use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
@@ -142,42 +134,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
142
134
None
143
135
} ;
144
136
145
- // Part 1: Is the Self type local?
146
- let self_ty_has_local_parent =
147
- ty_has_local_parent ( & impl_. self_ty . kind , cx, parent, parent_parent) ;
148
-
149
- if self_ty_has_local_parent {
150
- return ;
151
- }
152
-
153
- // Part 2: Is the Trait local?
154
- let of_trait_has_local_parent = impl_
155
- . of_trait
156
- . map ( |of_trait| path_has_local_parent ( of_trait. path , cx, parent, parent_parent) )
157
- . unwrap_or ( false ) ;
158
-
159
- if of_trait_has_local_parent {
160
- return ;
137
+ // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
138
+ // of the `impl` definition
139
+ let mut collector = PathCollector { paths : Vec :: new ( ) } ;
140
+ collector. visit_ty ( & impl_. self_ty ) ;
141
+ if let Some ( of_trait) = & impl_. of_trait {
142
+ collector. visit_trait_ref ( of_trait) ;
161
143
}
162
144
163
- // Part 3: Is the impl definition leaking outside it's defining scope?
164
- //
165
- // We always consider inherent impls to be leaking.
166
- let impl_has_enough_non_local_candidates = cx
167
- . tcx
168
- . impl_trait_ref ( def_id)
169
- . map ( |binder| {
170
- impl_trait_ref_has_enough_non_local_candidates (
171
- cx. tcx ,
172
- item. span ,
173
- def_id,
174
- binder,
175
- |did| did_has_local_parent ( did, cx. tcx , parent, parent_parent) ,
176
- )
177
- } )
178
- . unwrap_or ( false ) ;
179
-
180
- if impl_has_enough_non_local_candidates {
145
+ // 2. We check if any of path reference a "local" parent and if that the case
146
+ // we bail out as asked by T-lang, even though this isn't correct from a
147
+ // type-system point of view, as inference exists and could still leak the impl.
148
+ if collector
149
+ . paths
150
+ . iter ( )
151
+ . any ( |path| path_has_local_parent ( path, cx, parent, parent_parent) )
152
+ {
181
153
return ;
182
154
}
183
155
@@ -199,18 +171,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
199
171
let const_anon = matches ! ( parent_def_kind, DefKind :: Const | DefKind :: Static { .. } )
200
172
. then_some ( span_for_const_anon_suggestion) ;
201
173
202
- let may_remove = match & impl_. self_ty . kind {
203
- TyKind :: Ptr ( mut_ty) | TyKind :: Ref ( _, mut_ty)
204
- if ty_has_local_parent ( & mut_ty. ty . kind , cx, parent, parent_parent) =>
205
- {
206
- let type_ =
207
- if matches ! ( impl_. self_ty. kind, TyKind :: Ptr ( _) ) { "*" } else { "&" } ;
208
- let part = format ! ( "{}{}" , type_, mut_ty. mutbl. prefix_str( ) ) ;
209
- Some ( ( impl_. self_ty . span . shrink_to_lo ( ) . until ( mut_ty. ty . span ) , part) )
210
- }
211
- _ => None ,
212
- } ;
213
-
214
174
let impl_span = item. span . shrink_to_lo ( ) . to ( impl_. self_ty . span ) ;
215
175
let mut ms = MultiSpan :: from_span ( impl_span) ;
216
176
@@ -221,6 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
221
181
self_ty_span,
222
182
fluent:: lint_non_local_definitions_self_ty_not_local,
223
183
) ;
184
+
224
185
let of_trait_str = if let Some ( of_trait) = & impl_. of_trait {
225
186
ms. push_span_label (
226
187
path_span_without_args ( & of_trait. path ) ,
@@ -231,44 +192,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
231
192
None
232
193
} ;
233
194
234
- let ( doctest, move_to) = if is_at_toplevel_doctest ( ) {
235
- ( true , None )
236
- } else {
237
- let mut collector = PathCollector { paths : Vec :: new ( ) } ;
238
- collector. visit_ty ( & impl_. self_ty ) ;
239
- if let Some ( of_trait) = & impl_. of_trait {
240
- collector. visit_trait_ref ( of_trait) ;
241
- }
242
- collector. visit_generics ( & impl_. generics ) ;
243
-
244
- let mut may_move: Vec < Span > = collector
245
- . paths
246
- . into_iter ( )
247
- . filter_map ( |path| {
248
- if let Some ( did) = path. res . opt_def_id ( )
249
- && did_has_local_parent ( did, cx. tcx , parent, parent_parent)
250
- {
251
- Some ( cx. tcx . def_span ( did) )
252
- } else {
253
- None
254
- }
255
- } )
256
- . collect ( ) ;
257
- may_move. sort ( ) ;
258
- may_move. dedup ( ) ;
259
-
260
- let move_to = if may_move. is_empty ( ) {
261
- ms. push_span_label (
262
- cx. tcx . def_span ( parent) ,
263
- fluent:: lint_non_local_definitions_impl_move_help,
264
- ) ;
265
- None
266
- } else {
267
- Some ( ( cx. tcx . def_span ( parent) , may_move) )
268
- } ;
195
+ let doctest = is_at_toplevel_doctest ( ) ;
269
196
270
- ( false , move_to)
271
- } ;
197
+ if !doctest {
198
+ ms. push_span_label (
199
+ cx. tcx . def_span ( parent) ,
200
+ fluent:: lint_non_local_definitions_impl_move_help,
201
+ ) ;
202
+ }
272
203
273
204
let macro_to_change =
274
205
if let ExpnKind :: Macro ( kind, name) = item. span . ctxt ( ) . outer_expn_data ( ) . kind {
@@ -287,9 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
287
218
const_anon,
288
219
self_ty_str,
289
220
of_trait_str,
290
- move_to,
291
221
doctest,
292
- may_remove,
293
222
has_trait : impl_. of_trait . is_some ( ) ,
294
223
macro_to_change,
295
224
} )
@@ -316,90 +245,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
316
245
}
317
246
}
318
247
319
- // Detecting if the impl definition is leaking outside of its defining scope.
320
- //
321
- // Rule: for each impl, instantiate all local types with inference vars and
322
- // then assemble candidates for that goal, if there are more than 1 (non-private
323
- // impls), it does not leak.
324
- //
325
- // https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895
326
- fn impl_trait_ref_has_enough_non_local_candidates < ' tcx > (
327
- tcx : TyCtxt < ' tcx > ,
328
- infer_span : Span ,
329
- trait_def_id : DefId ,
330
- binder : EarlyBinder < ' tcx , TraitRef < ' tcx > > ,
331
- mut did_has_local_parent : impl FnMut ( DefId ) -> bool ,
332
- ) -> bool {
333
- let infcx = tcx
334
- . infer_ctxt ( )
335
- // We use the new trait solver since the obligation we are trying to
336
- // prove here may overflow and those are fatal in the old trait solver.
337
- // Which is unacceptable for a lint.
338
- //
339
- // Thanksfully the part we use here are very similar to the
340
- // new-trait-solver-as-coherence, which is in stabilization.
341
- //
342
- // https://github.com/rust-lang/rust/issues/123573
343
- . with_next_trait_solver ( true )
344
- . build ( ) ;
345
-
346
- let trait_ref = binder. instantiate ( tcx, infcx. fresh_args_for_item ( infer_span, trait_def_id) ) ;
347
-
348
- let trait_ref = trait_ref. fold_with ( & mut ReplaceLocalTypesWithInfer {
349
- infcx : & infcx,
350
- infer_span,
351
- did_has_local_parent : & mut did_has_local_parent,
352
- } ) ;
353
-
354
- let poly_trait_obligation = Obligation :: new (
355
- tcx,
356
- ObligationCause :: dummy ( ) ,
357
- ty:: ParamEnv :: empty ( ) ,
358
- Binder :: dummy ( trait_ref) ,
359
- ) ;
360
-
361
- let ambiguities = compute_applicable_impls_for_diagnostics ( & infcx, & poly_trait_obligation) ;
362
-
363
- let mut it = ambiguities. iter ( ) . filter ( |ambi| match ambi {
364
- CandidateSource :: DefId ( did) => !did_has_local_parent ( * did) ,
365
- CandidateSource :: ParamEnv ( _) => unreachable ! ( ) ,
366
- } ) ;
367
-
368
- let _ = it. next ( ) ;
369
- it. next ( ) . is_some ( )
370
- }
371
-
372
- /// Replace every local type by inference variable.
373
- ///
374
- /// ```text
375
- /// <Global<Local> as std::cmp::PartialEq<Global<Local>>>
376
- /// to
377
- /// <Global<_> as std::cmp::PartialEq<Global<_>>>
378
- /// ```
379
- struct ReplaceLocalTypesWithInfer < ' a , ' tcx , F : FnMut ( DefId ) -> bool > {
380
- infcx : & ' a InferCtxt < ' tcx > ,
381
- did_has_local_parent : F ,
382
- infer_span : Span ,
383
- }
384
-
385
- impl < ' a , ' tcx , F : FnMut ( DefId ) -> bool > TypeFolder < TyCtxt < ' tcx > >
386
- for ReplaceLocalTypesWithInfer < ' a , ' tcx , F >
387
- {
388
- fn cx ( & self ) -> TyCtxt < ' tcx > {
389
- self . infcx . tcx
390
- }
391
-
392
- fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
393
- if let Some ( def) = t. ty_adt_def ( )
394
- && ( self . did_has_local_parent ) ( def. did ( ) )
395
- {
396
- self . infcx . next_ty_var ( self . infer_span )
397
- } else {
398
- t. super_fold_with ( self )
399
- }
400
- }
401
- }
402
-
403
248
/// Simple hir::Path collector
404
249
struct PathCollector < ' tcx > {
405
250
paths : Vec < Path < ' tcx > > ,
@@ -412,42 +257,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
412
257
}
413
258
}
414
259
415
- /// Given a `Ty` we check if the (outermost) type is local.
416
- fn ty_has_local_parent (
417
- ty_kind : & TyKind < ' _ > ,
418
- cx : & LateContext < ' _ > ,
419
- impl_parent : DefId ,
420
- impl_parent_parent : Option < DefId > ,
421
- ) -> bool {
422
- match ty_kind {
423
- TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
424
- path_has_local_parent ( ty_path, cx, impl_parent, impl_parent_parent)
425
- }
426
- TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => path_has_local_parent (
427
- principle_poly_trait_ref. 0 . trait_ref . path ,
428
- cx,
429
- impl_parent,
430
- impl_parent_parent,
431
- ) ,
432
- TyKind :: TraitObject ( [ ] , _, _)
433
- | TyKind :: InferDelegation ( _, _)
434
- | TyKind :: Slice ( _)
435
- | TyKind :: Array ( _, _)
436
- | TyKind :: Ptr ( _)
437
- | TyKind :: Ref ( _, _)
438
- | TyKind :: BareFn ( _)
439
- | TyKind :: Never
440
- | TyKind :: Tup ( _)
441
- | TyKind :: Path ( _)
442
- | TyKind :: Pat ( ..)
443
- | TyKind :: AnonAdt ( _)
444
- | TyKind :: OpaqueDef ( _, _, _)
445
- | TyKind :: Typeof ( _)
446
- | TyKind :: Infer
447
- | TyKind :: Err ( _) => false ,
448
- }
449
- }
450
-
451
260
/// Given a path and a parent impl def id, this checks if the if parent resolution
452
261
/// def id correspond to the def id of the parent impl definition.
453
262
///
0 commit comments