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