@@ -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;
139use 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 ;
1810
1911use crate :: lints:: { NonLocalDefinitionsCargoUpdateNote , NonLocalDefinitionsDiag } ;
2012use crate :: { fluent_generated as fluent, LateContext , LateLintPass , LintContext } ;
@@ -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 {
@@ -290,9 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
290221 const_anon,
291222 self_ty_str,
292223 of_trait_str,
293- move_to,
294224 doctest,
295- may_remove,
296225 has_trait : impl_. of_trait . is_some ( ) ,
297226 macro_to_change,
298227 } ,
@@ -320,90 +249,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
320249 }
321250}
322251
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-
407252/// Simple hir::Path collector
408253struct PathCollector < ' tcx > {
409254 paths : Vec < Path < ' tcx > > ,
@@ -416,42 +261,6 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
416261 }
417262}
418263
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-
455264/// Given a path and a parent impl def id, this checks if the if parent resolution
456265/// def id correspond to the def id of the parent impl definition.
457266///
0 commit comments