Skip to content

Commit 48f25fb

Browse files
committed
[wip] rustdoc: variances
1 parent 81217c5 commit 48f25fb

File tree

4 files changed

+119
-27
lines changed

4 files changed

+119
-27
lines changed

Diff for: src/librustdoc/clean/auto_trait.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ where
106106
self.cx,
107107
tcx.generics_of(item_def_id),
108108
ty::GenericPredicates::default(),
109-
item_def_id,
109+
item_def_id, // FIXME: ofc its DefKind is not an impl confusing the variance compution
110110
);
111111
let params = raw_generics.params;
112112

@@ -457,7 +457,7 @@ where
457457
self.cx,
458458
tcx.generics_of(item_def_id),
459459
tcx.explicit_predicates_of(item_def_id),
460-
item_def_id,
460+
item_def_id, // FIXME: ofc its DefKind is not an impl confusing the variance compution
461461
);
462462
let mut generic_params = raw_generics.params;
463463

Diff for: src/librustdoc/clean/mod.rs

+94-23
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ fn clean_where_predicate<'tcx>(
322322
let bound_params = wbp
323323
.bound_generic_params
324324
.iter()
325-
.map(|param| clean_generic_param(cx, None, param))
325+
.map(|param| clean_generic_param(cx, param, None, None))
326326
.collect();
327327
WherePredicate::BoundPredicate {
328328
ty: clean_ty(wbp.bounded_ty, cx),
@@ -503,11 +503,12 @@ fn projection_to_path_segment<'tcx>(
503503

504504
fn clean_generic_param_def<'tcx>(
505505
def: &ty::GenericParamDef,
506+
variance: Option<ty::Variance>,
506507
cx: &mut DocContext<'tcx>,
507508
) -> GenericParamDef {
508509
let (name, kind) = match def.kind {
509510
ty::GenericParamDefKind::Lifetime => {
510-
(def.name, LifetimeParam { outlives: ThinVec::new() }.into())
511+
(def.name, LifetimeParam { variance, outlives: ThinVec::new() }.into())
511512
}
512513
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
513514
let default = has_default.then(|| {
@@ -521,6 +522,7 @@ fn clean_generic_param_def<'tcx>(
521522
(
522523
def.name,
523524
TypeParam {
525+
variance,
524526
bounds: ThinVec::new(), // These are filled in from the where-clause.
525527
default,
526528
synthetic,
@@ -556,8 +558,9 @@ fn clean_generic_param_def<'tcx>(
556558

557559
fn clean_generic_param<'tcx>(
558560
cx: &mut DocContext<'tcx>,
559-
generics: Option<&hir::Generics<'tcx>>,
560561
param: &hir::GenericParam<'tcx>,
562+
variance: Option<ty::Variance>,
563+
generics: Option<&hir::Generics<'tcx>>,
561564
) -> GenericParamDef {
562565
let (name, kind) = match param.kind {
563566
hir::GenericParamKind::Lifetime { .. } => {
@@ -574,7 +577,7 @@ fn clean_generic_param<'tcx>(
574577
} else {
575578
ThinVec::new()
576579
};
577-
(param.name.ident().name, LifetimeParam { outlives }.into())
580+
(param.name.ident().name, LifetimeParam { variance, outlives }.into())
578581
}
579582
hir::GenericParamKind::Type { ref default, synthetic } => {
580583
let bounds = if let Some(generics) = generics {
@@ -589,7 +592,13 @@ fn clean_generic_param<'tcx>(
589592
};
590593
(
591594
param.name.ident().name,
592-
TypeParam { bounds, default: default.map(|t| clean_ty(t, cx)), synthetic }.into(),
595+
TypeParam {
596+
variance,
597+
bounds,
598+
default: default.map(|t| clean_ty(t, cx)),
599+
synthetic,
600+
}
601+
.into(),
593602
)
594603
}
595604
hir::GenericParamKind::Const { ty, default, is_host_effect } => (
@@ -627,14 +636,42 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
627636
pub(crate) fn clean_generics<'tcx>(
628637
generics: &hir::Generics<'tcx>,
629638
cx: &mut DocContext<'tcx>,
630-
_item_def_id: DefId,
639+
item_def_id: DefId,
631640
) -> Generics {
641+
// FIXME(fmease): Instead of querying the defkind, we could instead let the caller make the decision
642+
// NOTE: This would also fix us rendering variances in synthetic impls which use the
643+
// DefId of the ADT.
644+
// FIXME(fmease): Add DefKind::TyAlias if type_alias_is_lazy()
645+
let def_kind = cx.tcx.def_kind(item_def_id);
646+
let variances = if !generics.params.is_empty()
647+
&& let DefKind::Fn
648+
| DefKind::AssocFn
649+
| DefKind::Enum
650+
| DefKind::Struct
651+
| DefKind::Union
652+
| DefKind::OpaqueTy = def_kind
653+
{
654+
let variances = cx.tcx.variances_of(item_def_id);
655+
let generics = cx.tcx.generics_of(item_def_id);
656+
657+
eprintln!("::: item={item_def_id:?} params={:?}", generics.params);
658+
eprintln!("--> variances_raw={variances:?}");
659+
660+
Some((variances, generics))
661+
} else {
662+
None
663+
};
664+
632665
let impl_trait_params = generics
633666
.params
634667
.iter()
635-
.filter(|param| is_impl_trait(param))
636-
.map(|param| {
637-
let param = clean_generic_param(cx, Some(generics), param);
668+
.enumerate()
669+
.filter(|(_, param)| is_impl_trait(param))
670+
.map(|(_index, param)| {
671+
// FIXME: this isn't correct for AssocFn since the variances also contain the parent variances, cut them off
672+
// let variance = variances.map(|variances| variances[index]); // FIXME(fmease): impl
673+
let variance = None;
674+
let param = clean_generic_param(cx, param, variance, Some(generics));
638675
let GenericParamDefKind::Type(ty_param) = &param.kind else { unreachable!() };
639676
cx.impl_trait_bounds.insert(param.def_id.into(), ty_param.bounds.to_vec());
640677
param
@@ -692,7 +729,12 @@ pub(crate) fn clean_generics<'tcx>(
692729
// bounds in the where predicates. If so, we move their bounds into the where predicates
693730
// while also preventing duplicates.
694731
for param in generics.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
695-
let mut param = clean_generic_param(cx, Some(generics), param);
732+
let variance = variances.and_then(|(variances, generics)| {
733+
let index = generics.param_def_id_to_index.get(&param.def_id.to_def_id())?;
734+
Some(variances[*index as usize])
735+
});
736+
let mut param = clean_generic_param(cx, param, variance, Some(generics));
737+
696738
match &mut param.kind {
697739
GenericParamDefKind::Lifetime(lt_param) => {
698740
if let Some(region_pred) = region_predicates.get_mut(&Lifetime(param.name)) {
@@ -746,8 +788,25 @@ fn clean_ty_generics<'tcx>(
746788
cx: &mut DocContext<'tcx>,
747789
generics: &ty::Generics,
748790
predicates: ty::GenericPredicates<'tcx>,
749-
_item_def_id: DefId,
791+
item_def_id: DefId,
750792
) -> Generics {
793+
// FIXME(fmease): Instead of querying the defkind, we could instead let the caller make the decision
794+
// NOTE: This would also fix us rendering variances in synthetic impls which use the
795+
// DefId of the ADT.
796+
// FIXME(fmease): Add DefKind::TyAlias if type_alias_is_lazy()
797+
let variances = if !generics.params.is_empty()
798+
&& let DefKind::Fn
799+
| DefKind::AssocFn
800+
| DefKind::Enum
801+
| DefKind::Struct
802+
| DefKind::Union
803+
| DefKind::OpaqueTy = cx.tcx.def_kind(item_def_id)
804+
{
805+
Some(cx.tcx.variances_of(item_def_id))
806+
} else {
807+
None
808+
};
809+
751810
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
752811
// since `Clean for ty::Predicate` would consume them.
753812
let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
@@ -758,22 +817,28 @@ fn clean_ty_generics<'tcx>(
758817
let stripped_params = generics
759818
.params
760819
.iter()
761-
.filter_map(|param| match param.kind {
762-
ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
763-
ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
820+
.filter(|param| match param.kind {
821+
ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
764822
ty::GenericParamDefKind::Type { synthetic, .. } => {
765823
if param.name == kw::SelfUpper {
766824
assert_eq!(param.index, 0);
767-
return None;
825+
return false;
768826
}
769827
if synthetic {
770828
impl_trait.insert(param.index.into(), vec![]);
771-
return None;
829+
return false;
772830
}
773-
Some(clean_generic_param_def(param, cx))
831+
true
774832
}
775-
ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
776-
ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
833+
ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
834+
})
835+
.map(|param| {
836+
// FIXME(fmease): We will probably handle AssocFn incorrectly since it has
837+
// parent generics (we prob need to offset shit)
838+
let variance = variances
839+
.map(|variances| variances[generics.param_def_id_to_index[&param.def_id] as usize]);
840+
841+
clean_generic_param_def(param, variance, cx)
777842
})
778843
.collect::<ThinVec<GenericParamDef>>();
779844

@@ -1222,7 +1287,7 @@ fn clean_poly_trait_ref<'tcx>(
12221287
.bound_generic_params
12231288
.iter()
12241289
.filter(|p| !is_elided_lifetime(p))
1225-
.map(|x| clean_generic_param(cx, None, x))
1290+
.map(|x| clean_generic_param(cx, x, None, None))
12261291
.collect(),
12271292
}
12281293
}
@@ -2566,7 +2631,7 @@ fn clean_bare_fn_ty<'tcx>(
25662631
.generic_params
25672632
.iter()
25682633
.filter(|p| !is_elided_lifetime(p))
2569-
.map(|x| clean_generic_param(cx, None, x))
2634+
.map(|x| clean_generic_param(cx, x, None, None)) // FIXME(fmease): variance?
25702635
.collect();
25712636
let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
25722637
let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
@@ -3152,8 +3217,14 @@ fn clean_bound_vars<'tcx>(
31523217
Some(GenericParamDef {
31533218
name,
31543219
def_id,
3155-
kind: TypeParam { bounds: ThinVec::new(), default: None, synthetic: false }
3156-
.into(),
3220+
// FIXME(fmease): higher-ranked generic params don't have a variance, right?
3221+
kind: TypeParam {
3222+
variance: None,
3223+
bounds: ThinVec::new(),
3224+
default: None,
3225+
synthetic: false,
3226+
}
3227+
.into(),
31573228
})
31583229
}
31593230
// FIXME(non_lifetime_binders): Support higher-ranked const parameters.

Diff for: src/librustdoc/clean/types.rs

+5-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,9 @@ 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+
// FIXME(fmease): Don't use a fixed variance.
1388+
let param = LifetimeParam { variance: None, outlives: ThinVec::new() };
1389+
Self { name, def_id, kind: param.into() }
13861390
}
13871391

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

Diff for: src/librustdoc/html/format.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,10 @@ impl clean::GenericParamDef {
189189
) -> impl Display + 'a + Captures<'tcx> {
190190
display_fn(move |f| match &self.kind {
191191
clean::GenericParamDefKind::Lifetime(param) => {
192-
write!(f, "{}", self.name)?;
192+
if let Some(variance) = param.variance {
193+
f.write_str(print_variance(variance))?;
194+
}
195+
f.write_str(self.name.as_str())?;
193196

194197
if !param.outlives.is_empty() {
195198
f.write_str(": ")?;
@@ -204,6 +207,9 @@ impl clean::GenericParamDef {
204207
Ok(())
205208
}
206209
clean::GenericParamDefKind::Type(param) => {
210+
if let Some(variance) = param.variance {
211+
f.write_str(print_variance(variance))?;
212+
}
207213
f.write_str(self.name.as_str())?;
208214

209215
if !param.bounds.is_empty() {
@@ -1749,6 +1755,17 @@ impl clean::Term {
17491755
}
17501756
}
17511757

1758+
// FIXME(fmease): Do we need to care about alternate?
1759+
fn print_variance(variance: ty::Variance) -> &'static str {
1760+
match variance {
1761+
// ty::Variance::Covariant => "",
1762+
ty::Variance::Covariant => "<sub class=\"variance\">+</sub>", // FIXME: temporary
1763+
ty::Variance::Invariant => r#"<sub class="variance" title="invariant">∘</sub>"#,
1764+
ty::Variance::Contravariant => r#"<sub class="variance" title="contravariant">−</sub>"#,
1765+
ty::Variance::Bivariant => r#"<sub class="variance" title="bivariant">∗</sub>"#,
1766+
}
1767+
}
1768+
17521769
pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display {
17531770
struct WithFormatter<F>(Cell<Option<F>>);
17541771

0 commit comments

Comments
 (0)