@@ -5,10 +5,10 @@ use hir::def::DefKind;
55use rustc_ast:: { self as ast, Delegation , DelegationSource , NodeId } ;
66use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
77use rustc_hir as hir;
8- use rustc_middle:: ty:: Ty ;
8+ use rustc_middle:: ty:: { Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor } ;
99use rustc_middle:: { span_bug, ty} ;
1010use rustc_span:: def_id:: { DefId , LocalDefId } ;
11- use rustc_span:: { ErrorGuaranteed , Span , kw } ;
11+ use rustc_span:: { ErrorGuaranteed , Span } ;
1212
1313use crate :: delegation:: generics:: GenericsGenerationResults ;
1414use crate :: delegation:: resolution:: resolver:: DelegationResolver ;
@@ -31,7 +31,7 @@ pub(super) struct ParamInfo {
3131 pub splatted : Option < u8 > ,
3232}
3333
34- #[ derive( Default ) ]
34+ #[ derive( Default , Debug ) ]
3535pub ( super ) struct SigMapping {
3636 pub map_return : bool ,
3737 pub arguments_to_map : FxIndexSet < usize > ,
@@ -254,17 +254,54 @@ impl<'tcx> DelegationResolver<'_, 'tcx> {
254254 }
255255
256256 if self . can_perform_self_mapping ( delegation, parent) ? {
257- // FIXME(fn_delegation): support heuristics for mapping of complex
258- // return types: `Self` -> `Box<Arc<Rc<Self>>>`
259- mapping. map_return = sig. output ( ) . is_param ( 0 ) ;
257+ /// Finds `Self` generic param only in ADT or references, so we avoid cases like
258+ /// `Self::Item` which will return true if `output.contains(...)` will be used.
259+ struct SelfFinder ;
260+
261+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for SelfFinder {
262+ type Result = ControlFlow < ( ) > ;
263+
264+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
265+ match t. kind ( ) {
266+ ty:: Adt ( _, args) => {
267+ if args
268+ . iter ( )
269+ . flat_map ( |arg| arg. as_type ( ) )
270+ . any ( |type_arg| type_arg. is_self_param ( ) )
271+ {
272+ return ControlFlow :: Break ( ( ) ) ;
273+ }
274+
275+ t. super_visit_with ( self )
276+ }
277+ ty:: Ref ( _, ref_t, _) => {
278+ if ref_t. is_self_param ( ) {
279+ return ControlFlow :: Break ( ( ) ) ;
280+ }
281+
282+ t. super_visit_with ( self )
283+ }
284+ _ => ControlFlow :: Continue ( ( ) ) ,
285+ }
286+ }
287+ }
288+
289+ impl SelfFinder {
290+ fn contains_self ( t : Ty < ' _ > ) -> bool {
291+ t. is_self_param ( ) || t. visit_with ( & mut SelfFinder ) . is_break ( )
292+ }
293+ }
294+
295+ let output = sig. output ( ) ;
296+
297+ mapping. map_return = SelfFinder :: contains_self ( output) ;
260298
261- let self_param = Ty :: new_param ( self . tcx ( ) , 0 , kw:: SelfUpper ) ;
262299 let arguments_to_map = sig
263300 . inputs ( )
264301 . iter ( )
265302 . enumerate ( )
266303 . skip ( 1 ) // Already checked above.
267- . filter_map ( |( idx, param) | param . contains ( self_param ) . then_some ( idx) ) ;
304+ . filter_map ( |( idx, & param) | SelfFinder :: contains_self ( param ) . then_some ( idx) ) ;
268305
269306 mapping. arguments_to_map . extend ( arguments_to_map) ;
270307 }
0 commit comments