@@ -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
9
use rustc_span:: { sym, ExpnKind , MacroKind , Span , Symbol } ;
14
- use rustc_trait_selection:: error_reporting:: traits:: ambiguity:: {
15
- compute_applicable_impls_for_diagnostics, CandidateSource ,
16
- } ;
17
- use rustc_trait_selection:: infer:: TyCtxtInferExt ;
18
10
19
11
use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
20
12
use crate :: { fluent_generated as fluent, LateContext , LateLintPass , LintContext } ;
@@ -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 {
@@ -290,9 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
290
221
const_anon,
291
222
self_ty_str,
292
223
of_trait_str,
293
- move_to,
294
224
doctest,
295
- may_remove,
296
225
has_trait : impl_. of_trait . is_some ( ) ,
297
226
macro_to_change,
298
227
} ,
@@ -320,90 +249,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
320
249
}
321
250
}
322
251
323
- // Detecting if the impl definition is leaking outside of its defining scope.
324
- //
325
- // Rule: for each impl, instantiate all local types with inference vars and
326
- // then assemble candidates for that goal, if there are more than 1 (non-private
327
- // impls), it does not leak.
328
- //
329
- // https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895
330
- fn impl_trait_ref_has_enough_non_local_candidates < ' tcx > (
331
- tcx : TyCtxt < ' tcx > ,
332
- infer_span : Span ,
333
- trait_def_id : DefId ,
334
- binder : EarlyBinder < ' tcx , TraitRef < ' tcx > > ,
335
- mut did_has_local_parent : impl FnMut ( DefId ) -> bool ,
336
- ) -> bool {
337
- let infcx = tcx
338
- . infer_ctxt ( )
339
- // We use the new trait solver since the obligation we are trying to
340
- // prove here may overflow and those are fatal in the old trait solver.
341
- // Which is unacceptable for a lint.
342
- //
343
- // Thanksfully the part we use here are very similar to the
344
- // new-trait-solver-as-coherence, which is in stabilization.
345
- //
346
- // https://github.com/rust-lang/rust/issues/123573
347
- . with_next_trait_solver ( true )
348
- . build ( ) ;
349
-
350
- let trait_ref = binder. instantiate ( tcx, infcx. fresh_args_for_item ( infer_span, trait_def_id) ) ;
351
-
352
- let trait_ref = trait_ref. fold_with ( & mut ReplaceLocalTypesWithInfer {
353
- infcx : & infcx,
354
- infer_span,
355
- did_has_local_parent : & mut did_has_local_parent,
356
- } ) ;
357
-
358
- let poly_trait_obligation = Obligation :: new (
359
- tcx,
360
- ObligationCause :: dummy ( ) ,
361
- ty:: ParamEnv :: empty ( ) ,
362
- Binder :: dummy ( trait_ref) ,
363
- ) ;
364
-
365
- let ambiguities = compute_applicable_impls_for_diagnostics ( & infcx, & poly_trait_obligation) ;
366
-
367
- let mut it = ambiguities. iter ( ) . filter ( |ambi| match ambi {
368
- CandidateSource :: DefId ( did) => !did_has_local_parent ( * did) ,
369
- CandidateSource :: ParamEnv ( _) => unreachable ! ( ) ,
370
- } ) ;
371
-
372
- let _ = it. next ( ) ;
373
- it. next ( ) . is_some ( )
374
- }
375
-
376
- /// Replace every local type by inference variable.
377
- ///
378
- /// ```text
379
- /// <Global<Local> as std::cmp::PartialEq<Global<Local>>>
380
- /// to
381
- /// <Global<_> as std::cmp::PartialEq<Global<_>>>
382
- /// ```
383
- struct ReplaceLocalTypesWithInfer < ' a , ' tcx , F : FnMut ( DefId ) -> bool > {
384
- infcx : & ' a InferCtxt < ' tcx > ,
385
- did_has_local_parent : F ,
386
- infer_span : Span ,
387
- }
388
-
389
- impl < ' a , ' tcx , F : FnMut ( DefId ) -> bool > TypeFolder < TyCtxt < ' tcx > >
390
- for ReplaceLocalTypesWithInfer < ' a , ' tcx , F >
391
- {
392
- fn cx ( & self ) -> TyCtxt < ' tcx > {
393
- self . infcx . tcx
394
- }
395
-
396
- fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
397
- if let Some ( def) = t. ty_adt_def ( )
398
- && ( self . did_has_local_parent ) ( def. did ( ) )
399
- {
400
- self . infcx . next_ty_var ( self . infer_span )
401
- } else {
402
- t. super_fold_with ( self )
403
- }
404
- }
405
- }
406
-
407
252
/// Simple hir::Path collector
408
253
struct PathCollector < ' tcx > {
409
254
paths : Vec < Path < ' tcx > > ,
@@ -416,42 +261,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
416
261
}
417
262
}
418
263
419
- /// Given a `Ty` we check if the (outermost) type is local.
420
- fn ty_has_local_parent (
421
- ty_kind : & TyKind < ' _ > ,
422
- cx : & LateContext < ' _ > ,
423
- impl_parent : DefId ,
424
- impl_parent_parent : Option < DefId > ,
425
- ) -> bool {
426
- match ty_kind {
427
- TyKind :: Path ( QPath :: Resolved ( _, ty_path) ) => {
428
- path_has_local_parent ( ty_path, cx, impl_parent, impl_parent_parent)
429
- }
430
- TyKind :: TraitObject ( [ principle_poly_trait_ref, ..] , _, _) => path_has_local_parent (
431
- principle_poly_trait_ref. 0 . trait_ref . path ,
432
- cx,
433
- impl_parent,
434
- impl_parent_parent,
435
- ) ,
436
- TyKind :: TraitObject ( [ ] , _, _)
437
- | TyKind :: InferDelegation ( _, _)
438
- | TyKind :: Slice ( _)
439
- | TyKind :: Array ( _, _)
440
- | TyKind :: Ptr ( _)
441
- | TyKind :: Ref ( _, _)
442
- | TyKind :: BareFn ( _)
443
- | TyKind :: Never
444
- | TyKind :: Tup ( _)
445
- | TyKind :: Path ( _)
446
- | TyKind :: Pat ( ..)
447
- | TyKind :: AnonAdt ( _)
448
- | TyKind :: OpaqueDef ( _, _, _)
449
- | TyKind :: Typeof ( _)
450
- | TyKind :: Infer
451
- | TyKind :: Err ( _) => false ,
452
- }
453
- }
454
-
455
264
/// Given a path and a parent impl def id, this checks if the if parent resolution
456
265
/// def id correspond to the def id of the parent impl definition.
457
266
///
0 commit comments