@@ -3,18 +3,11 @@ use rustc_hir::intravisit::{self, Visitor};
33use rustc_hir:: HirId ;
44use rustc_hir:: { def:: DefKind , Body , Item , ItemKind , Node , TyKind } ;
55use 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 ;
107use rustc_session:: { declare_lint, impl_lint_pass} ;
118use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
129use rustc_span:: Span ;
1310use rustc_span:: { sym, symbol:: kw, ExpnKind , MacroKind , 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 ;
1811
1912use crate :: fluent_generated as fluent;
2013use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
@@ -143,42 +136,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
143136 None
144137 } ;
145138
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) ;
162145 }
163146
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 though 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+ {
182155 return ;
183156 }
184157
@@ -200,18 +173,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
200173 let const_anon = matches ! ( parent_def_kind, DefKind :: Const | DefKind :: Static { .. } )
201174 . then_some ( span_for_const_anon_suggestion) ;
202175
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-
215176 let impl_span = item. span . shrink_to_lo ( ) . to ( impl_. self_ty . span ) ;
216177 let mut ms = MultiSpan :: from_span ( impl_span) ;
217178
@@ -222,6 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
222183 self_ty_span,
223184 fluent:: lint_non_local_definitions_self_ty_not_local,
224185 ) ;
186+
225187 let of_trait_str = if let Some ( of_trait) = & impl_. of_trait {
226188 ms. push_span_label (
227189 path_span_without_args ( & of_trait. path ) ,
@@ -232,44 +194,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
232194 None
233195 } ;
234196
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 ( ) ;
270198
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+ }
273205
274206 let macro_to_change =
275207 if let ExpnKind :: Macro ( kind, name) = item. span . ctxt ( ) . outer_expn_data ( ) . kind {
@@ -291,9 +223,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
291223 const_anon,
292224 self_ty_str,
293225 of_trait_str,
294- move_to,
295226 doctest,
296- may_remove,
297227 has_trait : impl_. of_trait . is_some ( ) ,
298228 macro_to_change,
299229 } ,
@@ -321,90 +251,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
321251 }
322252}
323253
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-
408254/// Simple hir::Path collector
409255struct PathCollector < ' tcx > {
410256 paths : Vec < Path < ' tcx > > ,
@@ -417,42 +263,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
417263 }
418264}
419265
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-
456266/// Given a path and a parent impl def id, this checks if the if parent resolution
457267/// def id correspond to the def id of the parent impl definition.
458268///
0 commit comments