Skip to content

Commit aa1a5e3

Browse files
committed
Simplify elision of default generic arguments
1 parent 4b859e6 commit aa1a5e3

File tree

1 file changed

+42
-48
lines changed

1 file changed

+42
-48
lines changed

src/librustdoc/clean/utils.rs

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ use rustc_hir::def::{DefKind, Res};
1616
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
1717
use rustc_metadata::rendered_const;
1818
use rustc_middle::mir;
19+
use rustc_middle::ty::TypeVisitableExt;
1920
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt};
20-
use rustc_middle::ty::{TypeVisitable, TypeVisitableExt};
2121
use rustc_span::symbol::{kw, sym, Symbol};
22+
use std::assert_matches::debug_assert_matches;
2223
use std::fmt::Write as _;
2324
use std::mem;
2425
use std::sync::LazyLock as Lazy;
@@ -108,57 +109,46 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
108109
std::borrow::Cow::from(args)
109110
};
110111

111-
let clean_arg = |(index, arg): (usize, &ty::GenericArg<'tcx>)| match arg.unpack() {
112-
GenericArgKind::Lifetime(lt) => {
113-
Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
112+
let clean_arg = |(index, &arg): (usize, &ty::GenericArg<'tcx>)| {
113+
// Elide the self type.
114+
if has_self && index == 0 {
115+
return None;
116+
}
117+
118+
// Elide internal host effect args.
119+
let param = generics.param_at(index, cx.tcx);
120+
if param.is_host_effect() {
121+
return None;
114122
}
115-
GenericArgKind::Type(_) if has_self && index == 0 => None,
116-
GenericArgKind::Type(ty) => {
117-
let ty = ty::Binder::bind_with_vars(ty, bound_vars);
118-
119-
if !elision_has_failed_once_before
120-
&& let Some(default) = generics.param_at(index, cx.tcx).default_value(cx.tcx)
121-
{
122-
let default = default.instantiate(cx.tcx, args.as_ref()).expect_ty();
123-
if can_elide_generic_arg(ty, ty.rebind(default)) {
124-
return None;
125-
}
126123

127-
elision_has_failed_once_before = true;
124+
let arg = ty::Binder::bind_with_vars(arg, bound_vars);
125+
126+
// Elide arguments that coincide with their default.
127+
if !elision_has_failed_once_before && let Some(default) = param.default_value(cx.tcx) {
128+
let default = default.instantiate(cx.tcx, args.as_ref());
129+
if can_elide_generic_arg(arg, arg.rebind(default)) {
130+
return None;
128131
}
132+
elision_has_failed_once_before = true;
133+
}
129134

130-
Some(GenericArg::Type(clean_middle_ty(
131-
ty,
135+
match arg.skip_binder().unpack() {
136+
GenericArgKind::Lifetime(lt) => {
137+
Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
138+
}
139+
GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(
140+
arg.rebind(ty),
132141
cx,
133142
None,
134143
Some(crate::clean::ContainerTy::Regular {
135144
ty: owner,
136-
args: ty.rebind(args.as_ref()),
145+
args: arg.rebind(args.as_ref()),
137146
arg: index,
138147
}),
139-
)))
140-
}
141-
GenericArgKind::Const(ct) => {
142-
if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } =
143-
generics.param_at(index, cx.tcx).kind
144-
{
145-
return None;
148+
))),
149+
GenericArgKind::Const(ct) => {
150+
Some(GenericArg::Const(Box::new(clean_middle_const(arg.rebind(ct), cx))))
146151
}
147-
148-
let ct = ty::Binder::bind_with_vars(ct, bound_vars);
149-
150-
if !elision_has_failed_once_before
151-
&& let Some(default) = generics.param_at(index, cx.tcx).default_value(cx.tcx)
152-
{
153-
let default = default.instantiate(cx.tcx, args.as_ref()).expect_const();
154-
if can_elide_generic_arg(ct, ct.rebind(default)) {
155-
return None;
156-
}
157-
158-
elision_has_failed_once_before = true;
159-
}
160-
161-
Some(GenericArg::Const(Box::new(clean_middle_const(ct, cx))))
162152
}
163153
};
164154

@@ -172,13 +162,17 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
172162
/// This uses a very conservative approach for performance and correctness reasons, meaning for
173163
/// several classes of terms it claims that they cannot be elided even if they theoretically could.
174164
/// This is absolutely fine since it mostly concerns edge cases.
175-
fn can_elide_generic_arg<'tcx, Term>(
176-
actual: ty::Binder<'tcx, Term>,
177-
default: ty::Binder<'tcx, Term>,
178-
) -> bool
179-
where
180-
Term: Eq + TypeVisitable<TyCtxt<'tcx>>,
181-
{
165+
fn can_elide_generic_arg<'tcx>(
166+
actual: ty::Binder<'tcx, ty::GenericArg<'tcx>>,
167+
default: ty::Binder<'tcx, ty::GenericArg<'tcx>>,
168+
) -> bool {
169+
debug_assert_matches!(
170+
(actual.skip_binder().unpack(), default.skip_binder().unpack()),
171+
(ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_))
172+
| (ty::GenericArgKind::Type(_), ty::GenericArgKind::Type(_))
173+
| (ty::GenericArgKind::Const(_), ty::GenericArgKind::Const(_))
174+
);
175+
182176
// In practice, we shouldn't have any inference variables at this point.
183177
// However to be safe, we bail out if we do happen to stumble upon them.
184178
if actual.has_infer() || default.has_infer() {

0 commit comments

Comments
 (0)