@@ -16,9 +16,10 @@ use rustc_hir::def::{DefKind, Res};
16
16
use rustc_hir:: def_id:: { DefId , LocalDefId , LOCAL_CRATE } ;
17
17
use rustc_metadata:: rendered_const;
18
18
use rustc_middle:: mir;
19
+ use rustc_middle:: ty:: TypeVisitableExt ;
19
20
use rustc_middle:: ty:: { self , GenericArgKind , GenericArgsRef , TyCtxt } ;
20
- use rustc_middle:: ty:: { TypeVisitable , TypeVisitableExt } ;
21
21
use rustc_span:: symbol:: { kw, sym, Symbol } ;
22
+ use std:: assert_matches:: debug_assert_matches;
22
23
use std:: fmt:: Write as _;
23
24
use std:: mem;
24
25
use std:: sync:: LazyLock as Lazy ;
@@ -75,94 +76,101 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
75
76
Crate { module, external_traits : cx. external_traits . clone ( ) }
76
77
}
77
78
78
- pub ( crate ) fn ty_args_to_args < ' tcx > (
79
+ pub ( crate ) fn clean_middle_generic_args < ' tcx > (
79
80
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 ,
82
83
owner : DefId ,
83
84
) -> 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 ( ) {
85
87
// Fast path which avoids executing the query `generics_of`.
86
88
return Vec :: new ( ) ;
87
89
}
88
90
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
+ } ;
91
106
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
+ }
94
113
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 ;
98
118
}
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
119
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 ;
112
127
}
128
+ elision_has_failed_once_before = true ;
129
+ }
113
130
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) ,
116
137
cx,
117
138
None ,
118
139
Some ( crate :: clean:: ContainerTy :: Regular {
119
140
ty : owner,
120
- args : ty_args,
121
- has_self,
141
+ args : arg. rebind ( args. as_ref ( ) ) ,
122
142
arg : index,
123
143
} ) ,
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) ) ) )
143
147
}
144
-
145
- Some ( GenericArg :: Const ( Box :: new ( clean_middle_const ( ty_args. rebind ( ct) , cx) ) ) )
146
148
}
147
149
} ;
148
150
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
152
156
}
153
157
154
158
/// Check if the generic argument `actual` coincides with the `default` and can therefore be elided.
155
159
///
156
160
/// This uses a very conservative approach for performance and correctness reasons, meaning for
157
161
/// several classes of terms it claims that they cannot be elided even if they theoretically could.
158
162
/// 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
+
166
174
// In practice, we shouldn't have any inference variables at this point.
167
175
// However to be safe, we bail out if we do happen to stumble upon them.
168
176
if actual. has_infer ( ) || default. has_infer ( ) {
@@ -192,14 +200,14 @@ where
192
200
actual. skip_binder ( ) == default. skip_binder ( )
193
201
}
194
202
195
- fn external_generic_args < ' tcx > (
203
+ fn clean_middle_generic_args_with_bindings < ' tcx > (
196
204
cx : & mut DocContext < ' tcx > ,
197
205
did : DefId ,
198
206
has_self : bool ,
199
207
bindings : ThinVec < TypeBinding > ,
200
208
ty_args : ty:: Binder < ' tcx , GenericArgsRef < ' tcx > > ,
201
209
) -> 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) ;
203
211
204
212
if cx. tcx . fn_trait_kind_from_def_id ( did) . is_some ( ) {
205
213
let ty = ty_args
@@ -225,7 +233,7 @@ fn external_generic_args<'tcx>(
225
233
}
226
234
}
227
235
228
- pub ( super ) fn external_path < ' tcx > (
236
+ pub ( super ) fn clean_middle_path < ' tcx > (
229
237
cx : & mut DocContext < ' tcx > ,
230
238
did : DefId ,
231
239
has_self : bool ,
@@ -238,7 +246,7 @@ pub(super) fn external_path<'tcx>(
238
246
res : Res :: Def ( def_kind, did) ,
239
247
segments : thin_vec ! [ PathSegment {
240
248
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) ,
242
250
} ] ,
243
251
}
244
252
}
0 commit comments