@@ -2,19 +2,11 @@ use rustc_errors::MultiSpan;
22use rustc_hir:: def:: DefKind ;
33use rustc_hir:: intravisit:: { self , Visitor } ;
44use 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 ;
106use rustc_session:: { declare_lint, impl_lint_pass} ;
117use rustc_span:: def_id:: { DefId , LOCAL_CRATE } ;
128use 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} ;
1810
1911use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
2012use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
@@ -142,42 +134,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
142134 None
143135 } ;
144136
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) ;
161143 }
162144
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+ {
181153 return ;
182154 }
183155
@@ -199,18 +171,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
199171 let const_anon = matches ! ( parent_def_kind, DefKind :: Const | DefKind :: Static { .. } )
200172 . then_some ( span_for_const_anon_suggestion) ;
201173
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-
214174 let impl_span = item. span . shrink_to_lo ( ) . to ( impl_. self_ty . span ) ;
215175 let mut ms = MultiSpan :: from_span ( impl_span) ;
216176
@@ -221,6 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
221181 self_ty_span,
222182 fluent:: lint_non_local_definitions_self_ty_not_local,
223183 ) ;
184+
224185 let of_trait_str = if let Some ( of_trait) = & impl_. of_trait {
225186 ms. push_span_label (
226187 path_span_without_args ( & of_trait. path ) ,
@@ -231,44 +192,14 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
231192 None
232193 } ;
233194
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 ( ) ;
269196
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+ }
272203
273204 let macro_to_change =
274205 if let ExpnKind :: Macro ( kind, name) = item. span . ctxt ( ) . outer_expn_data ( ) . kind {
@@ -287,9 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
287218 const_anon,
288219 self_ty_str,
289220 of_trait_str,
290- move_to,
291221 doctest,
292- may_remove,
293222 has_trait : impl_. of_trait . is_some ( ) ,
294223 macro_to_change,
295224 } )
@@ -316,90 +245,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
316245 }
317246}
318247
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-
403248/// Simple hir::Path collector
404249struct PathCollector < ' tcx > {
405250 paths : Vec < Path < ' tcx > > ,
@@ -412,42 +257,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
412257 }
413258}
414259
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-
451260/// Given a path and a parent impl def id, this checks if the if parent resolution
452261/// def id correspond to the def id of the parent impl definition.
453262///
0 commit comments