Skip to content

Commit 7406e00

Browse files
committed
rustdoc: clean: add support for variances
1 parent 23f9e1a commit 7406e00

File tree

3 files changed

+102
-22
lines changed

3 files changed

+102
-22
lines changed

src/librustdoc/clean/auto_trait.rs

+6
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ where
106106
self.cx,
107107
tcx.generics_of(item_def_id),
108108
ty::GenericPredicates::default(),
109+
// FIXME(fmease): This DefId isn't ideal since it stands for the implementing type, not
110+
// for the synthetic impl. The variance code has no way of knowing this and decides to
111+
// compute variances for the impl which we don't want.
109112
item_def_id,
110113
);
111114
let params = raw_generics.params;
@@ -457,6 +460,9 @@ where
457460
self.cx,
458461
tcx.generics_of(item_def_id),
459462
tcx.explicit_predicates_of(item_def_id),
463+
// FIXME(fmease): This DefId isn't ideal since it stands for the implementing type, not
464+
// for the synthetic impl. The variance code has no way of knowing this and decides to
465+
// compute variances for the impl which we don't want.
460466
item_def_id,
461467
);
462468
let mut generic_params = raw_generics.params;

src/librustdoc/clean/mod.rs

+92-21
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ fn clean_where_predicate<'tcx>(
321321
let bound_params = wbp
322322
.bound_generic_params
323323
.iter()
324-
.map(|param| clean_generic_param(cx, None, param))
324+
.map(|param| clean_generic_param(cx, param, None, None))
325325
.collect();
326326
WherePredicate::BoundPredicate {
327327
ty: clean_ty(wbp.bounded_ty, cx),
@@ -502,11 +502,12 @@ fn projection_to_path_segment<'tcx>(
502502

503503
fn clean_generic_param_def<'tcx>(
504504
def: &ty::GenericParamDef,
505+
variance: Option<ty::Variance>,
505506
cx: &mut DocContext<'tcx>,
506507
) -> GenericParamDef {
507508
let (name, kind) = match def.kind {
508509
ty::GenericParamDefKind::Lifetime => {
509-
(def.name, LifetimeParam { outlives: ThinVec::new() }.into())
510+
(def.name, LifetimeParam { variance, outlives: ThinVec::new() }.into())
510511
}
511512
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
512513
let default = has_default.then(|| {
@@ -520,6 +521,7 @@ fn clean_generic_param_def<'tcx>(
520521
(
521522
def.name,
522523
TypeParam {
524+
variance,
523525
bounds: ThinVec::new(), // These are filled in from the where-clause.
524526
default,
525527
synthetic,
@@ -555,8 +557,9 @@ fn clean_generic_param_def<'tcx>(
555557

556558
fn clean_generic_param<'tcx>(
557559
cx: &mut DocContext<'tcx>,
558-
generics: Option<&hir::Generics<'tcx>>,
559560
param: &hir::GenericParam<'tcx>,
561+
variance: Option<ty::Variance>,
562+
generics: Option<&hir::Generics<'tcx>>,
560563
) -> GenericParamDef {
561564
let (name, kind) = match param.kind {
562565
hir::GenericParamKind::Lifetime { .. } => {
@@ -573,7 +576,7 @@ fn clean_generic_param<'tcx>(
573576
} else {
574577
ThinVec::new()
575578
};
576-
(param.name.ident().name, LifetimeParam { outlives }.into())
579+
(param.name.ident().name, LifetimeParam { variance, outlives }.into())
577580
}
578581
hir::GenericParamKind::Type { ref default, synthetic } => {
579582
let bounds = if let Some(generics) = generics {
@@ -588,7 +591,13 @@ fn clean_generic_param<'tcx>(
588591
};
589592
(
590593
param.name.ident().name,
591-
TypeParam { bounds, default: default.map(|t| clean_ty(t, cx)), synthetic }.into(),
594+
TypeParam {
595+
variance,
596+
bounds,
597+
default: default.map(|t| clean_ty(t, cx)),
598+
synthetic,
599+
}
600+
.into(),
592601
)
593602
}
594603
hir::GenericParamKind::Const { ty, default, is_host_effect } => (
@@ -629,14 +638,43 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
629638
pub(crate) fn clean_generics<'tcx>(
630639
generics: &hir::Generics<'tcx>,
631640
cx: &mut DocContext<'tcx>,
632-
_item_def_id: DefId,
641+
item_def_id: DefId,
633642
) -> Generics {
643+
// FIXME(fmease): Instead of querying the DefKind, we could instead let the caller somehow make
644+
// the decision of whether to compute variances or not. Mostly relevant for synthetic impls but
645+
// also for function items since we probably want to *invert* the variances going forward.
646+
// FIXME(fmease): Add support for lazy type aliases (`DefKind::TyAlias if type_alias_is_lazy()`).
647+
let def_kind = cx.tcx.def_kind(item_def_id);
648+
let variances = if !generics.params.is_empty()
649+
&& let DefKind::Fn
650+
| DefKind::AssocFn
651+
| DefKind::Enum
652+
| DefKind::Struct
653+
| DefKind::Union
654+
| DefKind::OpaqueTy = def_kind
655+
{
656+
// We need to obtain the middle generics since we can't simply enumerate the HIR params when
657+
// iterating over them and index into the variances directly. We need to account for late-bound
658+
// regions and parent generics.
659+
let variances = cx.tcx.variances_of(item_def_id);
660+
let generics = cx.tcx.generics_of(item_def_id);
661+
Some((variances, generics))
662+
} else {
663+
None
664+
};
665+
634666
let impl_trait_params = generics
635667
.params
636668
.iter()
637669
.filter(|param| is_impl_trait(param))
638670
.map(|param| {
639-
let param = clean_generic_param(cx, Some(generics), param);
671+
let variance = variances.and_then(|(variances, generics)| {
672+
// The `param` might be late-bound in which case it doesn't have a variance associated
673+
// with it. Hence the fallible indexing.
674+
let index = *generics.param_def_id_to_index.get(&param.def_id.to_def_id())?;
675+
Some(variances[index as usize])
676+
});
677+
let param = clean_generic_param(cx, param, variance, Some(generics));
640678
let GenericParamDefKind::Type(ty_param) = &param.kind else { unreachable!() };
641679
cx.impl_trait_bounds.insert(param.def_id.into(), ty_param.bounds.to_vec());
642680
param
@@ -694,7 +732,14 @@ pub(crate) fn clean_generics<'tcx>(
694732
// bounds in the where predicates. If so, we move their bounds into the where predicates
695733
// while also preventing duplicates.
696734
for param in generics.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
697-
let mut param = clean_generic_param(cx, Some(generics), param);
735+
let variance = variances.and_then(|(variances, generics)| {
736+
// The `param` might be late-bound in which case it doesn't have a variance associated
737+
// with it. Hence the fallible indexing.
738+
let index = *generics.param_def_id_to_index.get(&param.def_id.to_def_id())?;
739+
Some(variances[index as usize])
740+
});
741+
let mut param = clean_generic_param(cx, param, variance, Some(generics));
742+
698743
match &mut param.kind {
699744
GenericParamDefKind::Lifetime(lt_param) => {
700745
if let Some(region_pred) = region_predicates.get_mut(&Lifetime(param.name)) {
@@ -748,8 +793,25 @@ fn clean_ty_generics<'tcx>(
748793
cx: &mut DocContext<'tcx>,
749794
generics: &ty::Generics,
750795
predicates: ty::GenericPredicates<'tcx>,
751-
_item_def_id: DefId,
796+
item_def_id: DefId,
752797
) -> Generics {
798+
// FIXME(fmease): Instead of querying the DefKind, we could instead let the caller somehow make
799+
// the decision of whether to compute variances or not. Mostly relevant for synthetic impls but
800+
// also for function items since we probably want to *invert* the variances going forward.
801+
// FIXME(fmease): Add support for lazy type aliases (`DefKind::TyAlias if type_alias_is_lazy()`).
802+
let variances = if !generics.params.is_empty()
803+
&& let DefKind::Fn
804+
| DefKind::AssocFn
805+
| DefKind::Enum
806+
| DefKind::Struct
807+
| DefKind::Union
808+
| DefKind::OpaqueTy = cx.tcx.def_kind(item_def_id)
809+
{
810+
Some(cx.tcx.variances_of(item_def_id))
811+
} else {
812+
None
813+
};
814+
753815
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
754816
// since `Clean for ty::Predicate` would consume them.
755817
let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
@@ -760,22 +822,26 @@ fn clean_ty_generics<'tcx>(
760822
let stripped_params = generics
761823
.params
762824
.iter()
763-
.filter_map(|param| match param.kind {
764-
ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
765-
ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
825+
.filter(|param| match param.kind {
826+
ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
766827
ty::GenericParamDefKind::Type { synthetic, .. } => {
767828
if param.name == kw::SelfUpper {
768829
assert_eq!(param.index, 0);
769-
return None;
830+
return false;
770831
}
771832
if synthetic {
772833
impl_trait.insert(param.index, vec![]);
773-
return None;
834+
return false;
774835
}
775-
Some(clean_generic_param_def(param, cx))
836+
true
776837
}
777-
ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
778-
ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
838+
ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
839+
})
840+
.map(|param| {
841+
let variance = variances
842+
.map(|variances| variances[generics.param_def_id_to_index[&param.def_id] as usize]);
843+
844+
clean_generic_param_def(param, variance, cx)
779845
})
780846
.collect::<ThinVec<GenericParamDef>>();
781847

@@ -1223,7 +1289,7 @@ fn clean_poly_trait_ref<'tcx>(
12231289
.bound_generic_params
12241290
.iter()
12251291
.filter(|p| !is_elided_lifetime(p))
1226-
.map(|x| clean_generic_param(cx, None, x))
1292+
.map(|x| clean_generic_param(cx, x, None, None))
12271293
.collect(),
12281294
}
12291295
}
@@ -2558,7 +2624,7 @@ fn clean_bare_fn_ty<'tcx>(
25582624
.generic_params
25592625
.iter()
25602626
.filter(|p| !is_elided_lifetime(p))
2561-
.map(|x| clean_generic_param(cx, None, x))
2627+
.map(|x| clean_generic_param(cx, x, None, None)) // FIXME(fmease): variance?
25622628
.collect();
25632629
let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
25642630
let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
@@ -3141,8 +3207,13 @@ fn clean_bound_vars<'tcx>(
31413207
Some(GenericParamDef {
31423208
name,
31433209
def_id,
3144-
kind: TypeParam { bounds: ThinVec::new(), default: None, synthetic: false }
3145-
.into(),
3210+
kind: TypeParam {
3211+
variance: None,
3212+
bounds: ThinVec::new(),
3213+
default: None,
3214+
synthetic: false,
3215+
}
3216+
.into(),
31463217
})
31473218
}
31483219
// FIXME(non_lifetime_binders): Support higher-ranked const parameters.

src/librustdoc/clean/types.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1356,11 +1356,13 @@ impl From<ConstParam> for GenericParamDefKind {
13561356

13571357
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
13581358
pub(crate) struct LifetimeParam {
1359+
pub(crate) variance: Option<ty::Variance>,
13591360
pub(crate) outlives: ThinVec<Lifetime>,
13601361
}
13611362

13621363
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
13631364
pub(crate) struct TypeParam {
1365+
pub(crate) variance: Option<ty::Variance>,
13641366
pub(crate) bounds: ThinVec<GenericBound>,
13651367
pub(crate) default: Option<Type>,
13661368
pub(crate) synthetic: bool,
@@ -1382,7 +1384,8 @@ pub(crate) struct GenericParamDef {
13821384

13831385
impl GenericParamDef {
13841386
pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1385-
Self { name, def_id, kind: LifetimeParam { outlives: ThinVec::new() }.into() }
1387+
let param = LifetimeParam { variance: None, outlives: ThinVec::new() };
1388+
Self { name, def_id, kind: param.into() }
13861389
}
13871390

13881391
pub(crate) fn is_synthetic_param(&self) -> bool {

0 commit comments

Comments
 (0)