Skip to content

Commit b44e1c3

Browse files
committed
[perf] only double-reverse default arguments
1 parent beb1b62 commit b44e1c3

File tree

1 file changed

+115
-68
lines changed

1 file changed

+115
-68
lines changed

src/librustdoc/clean/utils.rs

+115-68
Original file line numberDiff line numberDiff line change
@@ -83,85 +83,132 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
8383
pub(crate) fn ty_args_to_args<'tcx>(
8484
cx: &mut DocContext<'tcx>,
8585
ty_args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
86-
skip_first: bool,
86+
has_self: bool,
8787
container: Option<DefId>,
8888
) -> Vec<GenericArg> {
89+
let tcx = cx.tcx;
90+
let bound_vars = ty_args.bound_vars();
91+
let ty_args = ty_args.skip_binder();
92+
93+
let offset = if has_self { 1 } else { 0 };
94+
let mut args = Vec::with_capacity(ty_args.len().saturating_sub(offset));
95+
96+
let params = container.map(|container| &tcx.generics_of(container).params);
97+
let (req_args, opt_args) = if let Some(params) = params {
98+
let partition_point = params
99+
.iter()
100+
.rposition(|param| match param.kind {
101+
ty::GenericParamDefKind::Lifetime => false,
102+
ty::GenericParamDefKind::Type { has_default, .. } => has_default,
103+
ty::GenericParamDefKind::Const { has_default } => has_default,
104+
})
105+
// FIXME: using `offset` here might not be entirely correct
106+
.unwrap_or(offset);
107+
ty_args.split_at(partition_point)
108+
} else {
109+
(ty_args, &[] as _)
110+
};
111+
112+
args.extend(req_args.iter().enumerate().filter_map(|(index, arg)| {
113+
ty_arg_to_arg(cx, index, arg, has_self, container, ty_args, bound_vars)
114+
}));
115+
116+
let skipped_self = args.len() != req_args.len();
89117
let param_env = ty::ParamEnv::empty();
90118
let cause = ObligationCause::dummy();
91-
let params = container.map(|container| &cx.tcx.generics_of(container).params);
92119
let mut elision_has_failed_once_before = false;
93120

94-
let offset = if skip_first { 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 skip_first && 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;
121+
args.extend(
122+
(req_args.len()..ty_args.len())
123+
.zip(opt_args)
124+
.rev()
125+
.filter(|&(index, arg)| match arg.unpack() {
126+
GenericArgKind::Lifetime(_) => true,
127+
GenericArgKind::Type(ty) => {
128+
if !elision_has_failed_once_before
129+
&& let Some(params) = params
130+
&& let Some(default) = params[index].default_value(tcx)
131+
{
132+
let default = default.instantiate(tcx, ty_args).expect_ty();
133+
134+
if can_elide_generic_arg(
135+
tcx,
136+
&cause,
137+
param_env,
138+
ty::Binder::bind_with_vars(ty, bound_vars),
139+
ty::Binder::bind_with_vars(default, bound_vars),
140+
params[index].def_id,
141+
) {
142+
return false
143+
}
144+
145+
elision_has_failed_once_before = true;
146+
}
147+
148+
true
119149
}
120-
121-
elision_has_failed_once_before = true;
122-
}
123-
124-
Some(GenericArg::Type(clean_middle_ty(
125-
ty_args.rebind(ty),
126-
cx,
127-
None,
128-
container.map(|container| crate::clean::ContainerTy::Regular {
129-
ty: container,
130-
args: ty_args,
131-
arg: index,
132-
}),
133-
)))
134-
}
135-
GenericArgKind::Const(ct) => {
136-
if !elision_has_failed_once_before
137-
&& let Some(params) = params
138-
&& let Some(default) = params[index].default_value(cx.tcx)
139-
{
140-
let default =
141-
ty_args.map_bound(|args| default.instantiate(cx.tcx, args).expect_const());
142-
143-
if can_elide_generic_arg(
144-
cx.tcx,
145-
&cause,
146-
param_env,
147-
ty_args.rebind(ct),
148-
default,
149-
params[index].def_id,
150-
) {
151-
return None;
150+
GenericArgKind::Const(ct) => {
151+
if !elision_has_failed_once_before
152+
&& let Some(params) = params
153+
&& let Some(default) = params[index].default_value(tcx)
154+
{
155+
let default = default.instantiate(tcx, ty_args).expect_const();
156+
157+
if can_elide_generic_arg(
158+
tcx,
159+
&cause,
160+
param_env,
161+
ty::Binder::bind_with_vars(ct, bound_vars),
162+
ty::Binder::bind_with_vars(default, bound_vars),
163+
params[index].def_id,
164+
) {
165+
return false;
166+
}
167+
168+
elision_has_failed_once_before = true;
169+
}
170+
171+
true
152172
}
173+
})
174+
.filter_map(|(index, arg)| {
175+
ty_arg_to_arg(cx, index, arg, false, container, ty_args, bound_vars)
176+
}),
177+
);
178+
args[req_args.len().saturating_sub(if skipped_self { 1 } else { 0 })..].reverse();
153179

154-
elision_has_failed_once_before = true;
155-
}
180+
args
181+
}
156182

157-
Some(GenericArg::Const(Box::new(clean_middle_const(ty_args.rebind(ct), cx))))
183+
fn ty_arg_to_arg<'tcx>(
184+
cx: &mut DocContext<'tcx>,
185+
index: usize,
186+
arg: &ty::GenericArg<'tcx>,
187+
has_self: bool,
188+
container: Option<DefId>,
189+
ty_args: &'tcx [ty::GenericArg<'tcx>],
190+
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
191+
) -> Option<GenericArg> {
192+
match arg.unpack() {
193+
GenericArgKind::Lifetime(lt) => {
194+
Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
158195
}
159-
};
160-
161-
// FIXME(fmease): This doesn't look performant to me!
162-
args.extend(ty_args.skip_binder().iter().enumerate().rev().filter_map(ty_arg_to_arg));
163-
args.reverse();
164-
args
196+
GenericArgKind::Type(_) if has_self && index == 0 => None,
197+
GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(
198+
ty::Binder::bind_with_vars(ty, bound_vars),
199+
cx,
200+
None,
201+
container.map(|container| crate::clean::ContainerTy::Regular {
202+
ty: container,
203+
args: ty::Binder::bind_with_vars(ty_args, bound_vars),
204+
arg: index,
205+
}),
206+
))),
207+
GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(clean_middle_const(
208+
ty::Binder::bind_with_vars(ct, bound_vars),
209+
cx,
210+
)))),
211+
}
165212
}
166213

167214
fn can_elide_generic_arg<'tcx, T: ToTrace<'tcx> + TypeVisitable<TyCtxt<'tcx>>>(

0 commit comments

Comments
 (0)