@@ -16,9 +16,10 @@ use rustc_hir::def::{DefKind, Res};
1616use rustc_hir:: def_id:: { DefId , LocalDefId , LOCAL_CRATE } ;
1717use rustc_metadata:: rendered_const;
1818use rustc_middle:: mir;
19+ use rustc_middle:: ty:: TypeVisitableExt ;
1920use rustc_middle:: ty:: { self , GenericArgKind , GenericArgsRef , TyCtxt } ;
20- use rustc_middle:: ty:: { TypeVisitable , TypeVisitableExt } ;
2121use rustc_span:: symbol:: { kw, sym, Symbol } ;
22+ use std:: assert_matches:: debug_assert_matches;
2223use std:: fmt:: Write as _;
2324use std:: mem;
2425use std:: sync:: LazyLock as Lazy ;
@@ -75,94 +76,101 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
7576 Crate { module, external_traits : cx. external_traits . clone ( ) }
7677}
7778
78- pub ( crate ) fn ty_args_to_args < ' tcx > (
79+ pub ( crate ) fn clean_middle_generic_args < ' tcx > (
7980 cx : & mut DocContext < ' tcx > ,
80- ty_args : ty:: Binder < ' tcx , & ' tcx [ ty:: GenericArg < ' tcx > ] > ,
81- has_self : bool ,
81+ args : ty:: Binder < ' tcx , & ' tcx [ ty:: GenericArg < ' tcx > ] > ,
82+ mut has_self : bool ,
8283 owner : DefId ,
8384) -> Vec < GenericArg > {
84- if ty_args. skip_binder ( ) . is_empty ( ) {
85+ let ( args, bound_vars) = ( args. skip_binder ( ) , args. bound_vars ( ) ) ;
86+ if args. is_empty ( ) {
8587 // Fast path which avoids executing the query `generics_of`.
8688 return Vec :: new ( ) ;
8789 }
8890
89- let params = & cx. tcx . generics_of ( owner) . params ;
90- let mut elision_has_failed_once_before = false ;
91+ // If the container is a trait object type, the arguments won't contain the self type but the
92+ // generics of the corresponding trait will. In such a case, prepend a dummy self type in order
93+ // to align the arguments and parameters for the iteration below and to enable us to correctly
94+ // instantiate the generic parameter default later.
95+ let generics = cx. tcx . generics_of ( owner) ;
96+ let args = if !has_self && generics. parent . is_none ( ) && generics. has_self {
97+ has_self = true ;
98+ [ cx. tcx . types . trait_object_dummy_self . into ( ) ]
99+ . into_iter ( )
100+ . chain ( args. iter ( ) . copied ( ) )
101+ . collect :: < Vec < _ > > ( )
102+ . into ( )
103+ } else {
104+ std:: borrow:: Cow :: from ( args)
105+ } ;
91106
92- let offset = if has_self { 1 } else { 0 } ;
93- let mut args = Vec :: with_capacity ( ty_args. skip_binder ( ) . len ( ) . saturating_sub ( offset) ) ;
107+ let mut elision_has_failed_once_before = false ;
108+ let clean_arg = |( index, & arg) : ( usize , & ty:: GenericArg < ' tcx > ) | {
109+ // Elide the self type.
110+ if has_self && index == 0 {
111+ return None ;
112+ }
94113
95- let ty_arg_to_arg = |( index, arg) : ( usize , & ty:: GenericArg < ' tcx > ) | match arg. unpack ( ) {
96- GenericArgKind :: Lifetime ( lt) => {
97- Some ( GenericArg :: Lifetime ( clean_middle_region ( lt) . unwrap_or ( Lifetime :: elided ( ) ) ) )
114+ // Elide internal host effect args.
115+ let param = generics. param_at ( index, cx. tcx ) ;
116+ if param. is_host_effect ( ) {
117+ return None ;
98118 }
99- GenericArgKind :: Type ( _) if has_self && index == 0 => None ,
100- GenericArgKind :: Type ( ty) => {
101- if !elision_has_failed_once_before
102- && let Some ( default) = params[ index] . default_value ( cx. tcx )
103- {
104- let default =
105- ty_args. map_bound ( |args| default. instantiate ( cx. tcx , args) . expect_ty ( ) ) ;
106-
107- if can_elide_generic_arg ( ty_args. rebind ( ty) , default) {
108- return None ;
109- }
110119
111- elision_has_failed_once_before = true ;
120+ let arg = ty:: Binder :: bind_with_vars ( arg, bound_vars) ;
121+
122+ // Elide arguments that coincide with their default.
123+ if !elision_has_failed_once_before && let Some ( default) = param. default_value ( cx. tcx ) {
124+ let default = default. instantiate ( cx. tcx , args. as_ref ( ) ) ;
125+ if can_elide_generic_arg ( arg, arg. rebind ( default) ) {
126+ return None ;
112127 }
128+ elision_has_failed_once_before = true ;
129+ }
113130
114- Some ( GenericArg :: Type ( clean_middle_ty (
115- ty_args. rebind ( ty) ,
131+ match arg. skip_binder ( ) . unpack ( ) {
132+ GenericArgKind :: Lifetime ( lt) => {
133+ Some ( GenericArg :: Lifetime ( clean_middle_region ( lt) . unwrap_or ( Lifetime :: elided ( ) ) ) )
134+ }
135+ GenericArgKind :: Type ( ty) => Some ( GenericArg :: Type ( clean_middle_ty (
136+ arg. rebind ( ty) ,
116137 cx,
117138 None ,
118139 Some ( crate :: clean:: ContainerTy :: Regular {
119140 ty : owner,
120- args : ty_args,
121- has_self,
141+ args : arg. rebind ( args. as_ref ( ) ) ,
122142 arg : index,
123143 } ) ,
124- ) ) )
125- }
126- GenericArgKind :: Const ( ct) => {
127- if let ty:: GenericParamDefKind :: Const { is_host_effect : true , .. } = params[ index] . kind
128- {
129- return None ;
130- }
131-
132- if !elision_has_failed_once_before
133- && let Some ( default) = params[ index] . default_value ( cx. tcx )
134- {
135- let default =
136- ty_args. map_bound ( |args| default. instantiate ( cx. tcx , args) . expect_const ( ) ) ;
137-
138- if can_elide_generic_arg ( ty_args. rebind ( ct) , default) {
139- return None ;
140- }
141-
142- elision_has_failed_once_before = true ;
144+ ) ) ) ,
145+ GenericArgKind :: Const ( ct) => {
146+ Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( arg. rebind ( ct) , cx) ) ) )
143147 }
144-
145- Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( ty_args. rebind ( ct) , cx) ) ) )
146148 }
147149 } ;
148150
149- args. extend ( ty_args. skip_binder ( ) . iter ( ) . enumerate ( ) . rev ( ) . filter_map ( ty_arg_to_arg) ) ;
150- args. reverse ( ) ;
151- args
151+ let offset = if has_self { 1 } else { 0 } ;
152+ let mut clean_args = Vec :: with_capacity ( args. len ( ) . saturating_sub ( offset) ) ;
153+ clean_args. extend ( args. iter ( ) . enumerate ( ) . rev ( ) . filter_map ( clean_arg) ) ;
154+ clean_args. reverse ( ) ;
155+ clean_args
152156}
153157
154158/// Check if the generic argument `actual` coincides with the `default` and can therefore be elided.
155159///
156160/// This uses a very conservative approach for performance and correctness reasons, meaning for
157161/// several classes of terms it claims that they cannot be elided even if they theoretically could.
158162/// This is absolutely fine since it mostly concerns edge cases.
159- fn can_elide_generic_arg < ' tcx , Term > (
160- actual : ty:: Binder < ' tcx , Term > ,
161- default : ty:: Binder < ' tcx , Term > ,
162- ) -> bool
163- where
164- Term : Eq + TypeVisitable < TyCtxt < ' tcx > > ,
165- {
163+ fn can_elide_generic_arg < ' tcx > (
164+ actual : ty:: Binder < ' tcx , ty:: GenericArg < ' tcx > > ,
165+ default : ty:: Binder < ' tcx , ty:: GenericArg < ' tcx > > ,
166+ ) -> bool {
167+ debug_assert_matches ! (
168+ ( actual. skip_binder( ) . unpack( ) , default . skip_binder( ) . unpack( ) ) ,
169+ ( ty:: GenericArgKind :: Lifetime ( _) , ty:: GenericArgKind :: Lifetime ( _) )
170+ | ( ty:: GenericArgKind :: Type ( _) , ty:: GenericArgKind :: Type ( _) )
171+ | ( ty:: GenericArgKind :: Const ( _) , ty:: GenericArgKind :: Const ( _) )
172+ ) ;
173+
166174 // In practice, we shouldn't have any inference variables at this point.
167175 // However to be safe, we bail out if we do happen to stumble upon them.
168176 if actual. has_infer ( ) || default. has_infer ( ) {
@@ -192,14 +200,14 @@ where
192200 actual. skip_binder ( ) == default. skip_binder ( )
193201}
194202
195- fn external_generic_args < ' tcx > (
203+ fn clean_middle_generic_args_with_bindings < ' tcx > (
196204 cx : & mut DocContext < ' tcx > ,
197205 did : DefId ,
198206 has_self : bool ,
199207 bindings : ThinVec < TypeBinding > ,
200208 ty_args : ty:: Binder < ' tcx , GenericArgsRef < ' tcx > > ,
201209) -> GenericArgs {
202- let args = ty_args_to_args ( cx, ty_args. map_bound ( |args| & args[ ..] ) , has_self, did) ;
210+ let args = clean_middle_generic_args ( cx, ty_args. map_bound ( |args| & args[ ..] ) , has_self, did) ;
203211
204212 if cx. tcx . fn_trait_kind_from_def_id ( did) . is_some ( ) {
205213 let ty = ty_args
@@ -225,7 +233,7 @@ fn external_generic_args<'tcx>(
225233 }
226234}
227235
228- pub ( super ) fn external_path < ' tcx > (
236+ pub ( super ) fn clean_middle_path < ' tcx > (
229237 cx : & mut DocContext < ' tcx > ,
230238 did : DefId ,
231239 has_self : bool ,
@@ -238,7 +246,7 @@ pub(super) fn external_path<'tcx>(
238246 res : Res :: Def ( def_kind, did) ,
239247 segments : thin_vec ! [ PathSegment {
240248 name,
241- args: external_generic_args ( cx, did, has_self, bindings, args) ,
249+ args: clean_middle_generic_args_with_bindings ( cx, did, has_self, bindings, args) ,
242250 } ] ,
243251 }
244252}
0 commit comments