@@ -14,10 +14,16 @@ use rustc_ast::tokenstream::TokenTree;
1414use rustc_hir as hir;
1515use rustc_hir:: def:: { DefKind , Res } ;
1616use rustc_hir:: def_id:: { DefId , LocalDefId , LOCAL_CRATE } ;
17+ use rustc_infer:: infer:: at:: ToTrace ;
18+ use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
1719use rustc_metadata:: rendered_const;
1820use rustc_middle:: mir;
21+ use rustc_middle:: traits:: ObligationCause ;
1922use rustc_middle:: ty:: { self , GenericArgKind , GenericArgsRef , TyCtxt } ;
23+ use rustc_middle:: ty:: { TypeVisitable , TypeVisitableExt } ;
2024use rustc_span:: symbol:: { kw, sym, Symbol } ;
25+ use rustc_trait_selection:: infer:: TyCtxtInferExt ;
26+ use rustc_trait_selection:: traits:: ObligationCtxt ;
2127use std:: fmt:: Write as _;
2228use std:: mem;
2329use std:: sync:: LazyLock as Lazy ;
@@ -76,40 +82,133 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
7682
7783pub ( crate ) fn ty_args_to_args < ' tcx > (
7884 cx : & mut DocContext < ' tcx > ,
79- args : ty:: Binder < ' tcx , & ' tcx [ ty:: GenericArg < ' tcx > ] > ,
85+ ty_args : ty:: Binder < ' tcx , & ' tcx [ ty:: GenericArg < ' tcx > ] > ,
8086 has_self : bool ,
8187 container : Option < DefId > ,
8288) -> 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
89+ let param_env = ty:: ParamEnv :: empty ( ) ;
90+ let cause = ObligationCause :: dummy ( ) ;
91+ let params = container. map ( |container| & cx. tcx . generics_of ( container) . params ) ;
92+ let mut elision_has_failed_once_before = false ;
93+
94+ let offset = if has_self { 1 } else { 0 } ;
95+ let mut args = Vec :: with_capacity ( ty_args. skip_binder ( ) . len ( ) . saturating_sub ( offset) ) ;
96+
97+ let ty_arg_to_arg = |( index, arg) : ( usize , & ty:: GenericArg < ' tcx > ) | match arg. unpack ( ) {
98+ GenericArgKind :: Lifetime ( lt) => {
99+ Some ( GenericArg :: Lifetime ( clean_middle_region ( lt) . unwrap_or ( Lifetime :: elided ( ) ) ) )
100+ }
101+ GenericArgKind :: Type ( _) if has_self && index == 0 => None ,
102+ GenericArgKind :: Type ( ty) => {
103+ if !elision_has_failed_once_before
104+ && let Some ( params) = params
105+ && let Some ( default) = params[ index] . default_value ( cx. tcx )
106+ {
107+ let default =
108+ ty_args. map_bound ( |args| default. instantiate ( cx. tcx , args) . expect_ty ( ) ) ;
109+
110+ if can_elide_generic_arg (
111+ cx. tcx ,
112+ & cause,
113+ param_env,
114+ ty_args. rebind ( ty) ,
115+ default,
116+ params[ index] . def_id ,
117+ ) {
118+ return None ;
119+ }
120+
121+ elision_has_failed_once_before = true ;
95122 }
96- GenericArgKind :: Type ( ty) => Some ( GenericArg :: Type ( clean_middle_ty (
97- kind. rebind ( ty) ,
123+
124+ Some ( GenericArg :: Type ( clean_middle_ty (
125+ ty_args. rebind ( ty) ,
98126 cx,
99127 None ,
100128 container. map ( |container| crate :: clean:: ContainerTy :: Regular {
101129 ty : container,
102- args,
130+ args : ty_args ,
103131 has_self,
104132 arg : index,
105133 } ) ,
106- ) ) ) ,
107- GenericArgKind :: Const ( ct) => {
108- Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( kind. rebind ( ct) , cx) ) ) )
134+ ) ) )
135+ }
136+ GenericArgKind :: Const ( ct) => {
137+ if !elision_has_failed_once_before
138+ && let Some ( params) = params
139+ && let Some ( default) = params[ index] . default_value ( cx. tcx )
140+ {
141+ let default =
142+ ty_args. map_bound ( |args| default. instantiate ( cx. tcx , args) . expect_const ( ) ) ;
143+
144+ if can_elide_generic_arg (
145+ cx. tcx ,
146+ & cause,
147+ param_env,
148+ ty_args. rebind ( ct) ,
149+ default,
150+ params[ index] . def_id ,
151+ ) {
152+ return None ;
153+ }
154+
155+ elision_has_failed_once_before = true ;
109156 }
157+
158+ Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( ty_args. rebind ( ct) , cx) ) ) )
110159 }
111- } ) ) ;
112- ret_val
160+ } ;
161+
162+ args. extend ( ty_args. skip_binder ( ) . iter ( ) . enumerate ( ) . rev ( ) . filter_map ( ty_arg_to_arg) ) ;
163+ args. reverse ( ) ;
164+ args
165+ }
166+
167+ /// Check if the generic argument `actual` coincides with the `default` and can therefore be elided.
168+ fn can_elide_generic_arg < ' tcx , T : ToTrace < ' tcx > + TypeVisitable < TyCtxt < ' tcx > > > (
169+ tcx : TyCtxt < ' tcx > ,
170+ cause : & ObligationCause < ' tcx > ,
171+ param_env : ty:: ParamEnv < ' tcx > ,
172+ actual : ty:: Binder < ' tcx , T > ,
173+ default : ty:: Binder < ' tcx , T > ,
174+ did : DefId ,
175+ ) -> bool {
176+ // The operations below are only correct if we don't have any inference variables.
177+ debug_assert ! ( !actual. has_infer( ) ) ;
178+ debug_assert ! ( !default . has_infer( ) ) ;
179+
180+ // Since we don't properly keep track of bound variables, don't attempt to make
181+ // any sense out of escaping bound variables (we just don't have enough context).
182+ if actual. has_escaping_bound_vars ( ) || default. has_escaping_bound_vars ( ) {
183+ return false ;
184+ }
185+
186+ // If the arguments contain projections or (non-escaping) late-bound regions, we have to examine
187+ // them more closely and can't take the fast path.
188+ // Having projections means that there's potential to be further normalized thereby revealing if
189+ // they are equal after all. Regarding late-bound regions, they can be liberated allowing us to
190+ // consider more types to be equal by ignoring the names of binders.
191+ if !actual. has_late_bound_regions ( )
192+ && !actual. has_projections ( )
193+ && !default. has_late_bound_regions ( )
194+ && !default. has_projections ( )
195+ {
196+ // Check the memory addresses of the interned arguments for equality.
197+ return actual. skip_binder ( ) == default. skip_binder ( ) ;
198+ }
199+
200+ let actual = tcx. liberate_late_bound_regions ( did, actual) ;
201+ let default = tcx. liberate_late_bound_regions ( did, default) ;
202+
203+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
204+ let ocx = ObligationCtxt :: new ( & infcx) ;
205+
206+ let actual = ocx. normalize ( cause, param_env, actual) ;
207+ let default = ocx. normalize ( cause, param_env, default) ;
208+
209+ ocx. eq ( cause, param_env, actual, default) . is_ok ( )
210+ && ocx. select_all_or_error ( ) . is_empty ( )
211+ && infcx. resolve_regions ( & OutlivesEnvironment :: new ( param_env) ) . is_empty ( )
113212}
114213
115214fn external_generic_args < ' tcx > (
0 commit comments