@@ -17,6 +17,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
1717use  rustc_metadata:: rendered_const; 
1818use  rustc_middle:: mir; 
1919use  rustc_middle:: ty:: { self ,  GenericArgKind ,  GenericArgsRef ,  TyCtxt } ; 
20+ use  rustc_middle:: ty:: { TypeVisitable ,  TypeVisitableExt } ; 
2021use  rustc_span:: symbol:: { kw,  sym,  Symbol } ; 
2122use  std:: fmt:: Write  as  _; 
2223use  std:: mem; 
@@ -76,44 +77,123 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
7677
7778pub ( crate )  fn  ty_args_to_args < ' tcx > ( 
7879    cx :  & mut  DocContext < ' tcx > , 
79-     args :  ty:: Binder < ' tcx ,  & ' tcx  [ ty:: GenericArg < ' tcx > ] > , 
80+     ty_args :  ty:: Binder < ' tcx ,  & ' tcx  [ ty:: GenericArg < ' tcx > ] > , 
8081    has_self :  bool , 
81-     container :   Option < DefId > , 
82+     owner :   DefId , 
8283)  -> Vec < GenericArg >  { 
83-     let  mut  skip_first = has_self; 
84-     let  mut  ret_val =
85-         Vec :: with_capacity ( args. skip_binder ( ) . len ( ) . saturating_sub ( if  skip_first {  1  }  else  {  0  } ) ) ; 
86- 
87-     ret_val. extend ( args. iter ( ) . enumerate ( ) . filter_map ( |( index,  kind) | { 
88-         match  kind. skip_binder ( ) . unpack ( )  { 
89-             GenericArgKind :: Lifetime ( lt)  => { 
90-                 Some ( GenericArg :: Lifetime ( clean_middle_region ( lt) . unwrap_or ( Lifetime :: elided ( ) ) ) ) 
91-             } 
92-             GenericArgKind :: Type ( _)  if  skip_first => { 
93-                 skip_first = false ; 
94-                 None 
84+     if  ty_args. skip_binder ( ) . is_empty ( )  { 
85+         // Fast path which avoids executing the query `generics_of`. 
86+         return  Vec :: new ( ) ; 
87+     } 
88+ 
89+     let  params = & cx. tcx . generics_of ( owner) . params ; 
90+     let  mut  elision_has_failed_once_before = false ; 
91+ 
92+     let  offset = if  has_self {  1  }  else  {  0  } ; 
93+     let  mut  args = Vec :: with_capacity ( ty_args. skip_binder ( ) . len ( ) . saturating_sub ( offset) ) ; 
94+ 
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 ( ) ) ) ) 
98+         } 
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+                 } 
110+ 
111+                 elision_has_failed_once_before = true ; 
95112            } 
96-             GenericArgKind :: Type ( ty)  => Some ( GenericArg :: Type ( clean_middle_ty ( 
97-                 kind. rebind ( ty) , 
113+ 
114+             Some ( GenericArg :: Type ( clean_middle_ty ( 
115+                 ty_args. rebind ( ty) , 
98116                cx, 
99117                None , 
100-                 container . map ( |container|  crate :: clean:: ContainerTy :: Regular  { 
101-                     ty :  container , 
102-                     args, 
118+                 Some ( crate :: clean:: ContainerTy :: Regular  { 
119+                     ty :  owner , 
120+                     args :  ty_args , 
103121                    has_self, 
104122                    arg :  index, 
105123                } ) , 
106-             ) ) ) , 
124+             ) ) ) 
125+         } 
126+         GenericArgKind :: Const ( ct)  => { 
107127            // FIXME(effects): this relies on the host effect being called `host`, which users could also name 
108128            // their const generics. 
109129            // FIXME(effects): this causes `host = true` and `host = false` generics to also be emitted. 
110-             GenericArgKind :: Const ( ct)  if  let  ty:: ConstKind :: Param ( p)  = ct. kind ( )  && p. name  == sym:: host => None , 
111-             GenericArgKind :: Const ( ct)  => { 
112-                 Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( kind. rebind ( ct) ,  cx) ) ) ) 
130+             if  let  ty:: ConstKind :: Param ( p)  = ct. kind ( ) 
131+                 && p. name  == sym:: host
132+             { 
133+                 return  None ; 
113134            } 
135+ 
136+             if  !elision_has_failed_once_before
137+                 && let  Some ( default)  = params[ index] . default_value ( cx. tcx ) 
138+             { 
139+                 let  default =
140+                     ty_args. map_bound ( |args| default. instantiate ( cx. tcx ,  args) . expect_const ( ) ) ; 
141+ 
142+                 if  can_elide_generic_arg ( ty_args. rebind ( ct) ,  default)  { 
143+                     return  None ; 
144+                 } 
145+ 
146+                 elision_has_failed_once_before = true ; 
147+             } 
148+ 
149+             Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( ty_args. rebind ( ct) ,  cx) ) ) ) 
114150        } 
115-     } ) ) ; 
116-     ret_val
151+     } ; 
152+ 
153+     args. extend ( ty_args. skip_binder ( ) . iter ( ) . enumerate ( ) . rev ( ) . filter_map ( ty_arg_to_arg) ) ; 
154+     args. reverse ( ) ; 
155+     args
156+ } 
157+ 
158+ /// Check if the generic argument `actual` coincides with the `default` and can therefore be elided. 
159+ /// 
160+ /// This uses a very conservative approach for performance and correctness reasons, meaning for 
161+ /// several classes of terms it claims that they cannot be elided even if they theoretically could. 
162+ /// This is absolutely fine since it mostly concerns edge cases. 
163+ fn  can_elide_generic_arg < ' tcx ,  Term > ( 
164+     actual :  ty:: Binder < ' tcx ,  Term > , 
165+     default :  ty:: Binder < ' tcx ,  Term > , 
166+ )  -> bool 
167+ where 
168+     Term :  Eq  + TypeVisitable < TyCtxt < ' tcx > > , 
169+ { 
170+     // In practice, we shouldn't have any inference variables at this point. 
171+     // However to be safe, we bail out if we do happen to stumble upon them. 
172+     if  actual. has_infer ( )  || default. has_infer ( )  { 
173+         return  false ; 
174+     } 
175+ 
176+     // Since we don't properly keep track of bound variables in rustdoc (yet), we don't attempt to 
177+     // make any sense out of escaping bound variables. We simply don't have enough context and it 
178+     // would be incorrect to try to do so anyway. 
179+     if  actual. has_escaping_bound_vars ( )  || default. has_escaping_bound_vars ( )  { 
180+         return  false ; 
181+     } 
182+ 
183+     // Theoretically we could now check if either term contains (non-escaping) late-bound regions or 
184+     // projections, relate the two using an `InferCtxt` and check if the resulting obligations hold. 
185+     // Having projections means that the terms can potentially be further normalized thereby possibly 
186+     // revealing that they are equal after all. Regarding late-bound regions, they could to be 
187+     // liberated allowing us to consider more types to be equal by ignoring the names of binders 
188+     // (e.g., `for<'a> TYPE<'a>` and `for<'b> TYPE<'b>`). 
189+     // 
190+     // However, we are mostly interested in “reeliding” generic args, i.e., eliding generic args that 
191+     // were originally elided by the user and later filled in by the compiler contrary to eliding 
192+     // arbitrary generic arguments if they happen to semantically coincide with the default (of course, 
193+     // we cannot possibly distinguish these two cases). Therefore and for performance reasons, it 
194+     // suffices to only perform a syntactic / structural check by comparing the memory addresses of 
195+     // the interned arguments. 
196+     actual. skip_binder ( )  == default. skip_binder ( ) 
117197} 
118198
119199fn  external_generic_args < ' tcx > ( 
@@ -123,7 +203,7 @@ fn external_generic_args<'tcx>(
123203    bindings :  ThinVec < TypeBinding > , 
124204    ty_args :  ty:: Binder < ' tcx ,  GenericArgsRef < ' tcx > > , 
125205)  -> GenericArgs  { 
126-     let  args = ty_args_to_args ( cx,  ty_args. map_bound ( |args| & args[ ..] ) ,  has_self,  Some ( did) ) ; 
206+     let  args = ty_args_to_args ( cx,  ty_args. map_bound ( |args| & args[ ..] ) ,  has_self,  did) ; 
127207
128208    if  cx. tcx . fn_trait_kind_from_def_id ( did) . is_some ( )  { 
129209        let  ty = ty_args
0 commit comments