Skip to content

Commit

Permalink
Auto merge of rust-lang#123219 - fmease:rustdoc-variances-json, r=<try>
Browse files Browse the repository at this point in the history
[WIP] rustdoc (base+json): add support for variances

I had this patch lying around for more than a month without much progress. Submitting this now to move things forward hopefully.

Addresses part of rust-lang#22108.

---

For transparency, I've stalled work on this because I haven't had the time to find ways to obtain or represent the “reason” / “provenance” of variances — a feature kindly requested by `@obi1kenobi,` maintainer of cargo-semver-checks. With “reason” we're referring to the set of constituent types that have had an influence on the variance of a given generic parameter.

This information could then be used in the diagnostics of cargo-semver-checks à la “variance of param `T` of ty `S` changed from covariant to contravariant because you changed the type of field `f` from `T` to `fn(T)”. On second thought, this seems like a major add-on and I fear that it's infeasible to implement this (smh. exposing the necessary info from rustc). On the other hand, this feature probably has a large impact on the design of the final API (i.e., how we represent variances in rustdoc JSON). I definitely don't want to hand-roll variance computation inside rustdoc.

---

TODOs:

* clean up the implementation (see individual FIXMEs)
* write docs for `rustdoc-json-types`
* add rustdoc JSON tests

r? ghost
  • Loading branch information
bors committed Mar 30, 2024
2 parents a3cfa03 + 3781173 commit 77b18b0
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 198 deletions.
20 changes: 14 additions & 6 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ where
self.cx,
tcx.generics_of(item_def_id),
ty::GenericPredicates::default(),
// FIXME(fmease): This DefId isn't ideal since it stands for the implementing type, not
// for the synthetic impl. The variance code has no way of knowing this and decides to
// compute variances for the impl which we don't want.
item_def_id,
);
let params = raw_generics.params;

Expand Down Expand Up @@ -456,6 +460,10 @@ where
self.cx,
tcx.generics_of(item_def_id),
tcx.explicit_predicates_of(item_def_id),
// FIXME(fmease): This DefId isn't ideal since it stands for the implementing type, not
// for the synthetic impl. The variance code has no way of knowing this and decides to
// compute variances for the impl which we don't want.
item_def_id,
);
let mut generic_params = raw_generics.params;

Expand Down Expand Up @@ -630,19 +638,19 @@ where
existing_predicates.extend(final_bounds);

for param in generic_params.iter_mut() {
match param.kind {
GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
match &mut param.kind {
GenericParamDefKind::Type(ty_param) => {
// We never want something like `impl<T=Foo>`.
default.take();
ty_param.default.take();
let generic_ty = Type::Generic(param.name);
if !has_sized.contains(&generic_ty) {
bounds.insert(0, GenericBound::maybe_sized(self.cx));
ty_param.bounds.insert(0, GenericBound::maybe_sized(self.cx));
}
}
GenericParamDefKind::Lifetime { .. } => {}
GenericParamDefKind::Const { ref mut default, .. } => {
GenericParamDefKind::Const(ct_param) => {
// We never want something like `impl<const N: usize = 10>`
default.take();
ct_param.default.take();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/clean/blanket_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
cx,
cx.tcx.generics_of(impl_def_id),
cx.tcx.explicit_predicates_of(impl_def_id),
impl_def_id,
),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
Expand Down
30 changes: 19 additions & 11 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
.collect();

let predicates = cx.tcx.predicates_of(did);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates, did);
let generics = filter_non_trait_generics(did, generics);
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
Expand All @@ -284,8 +284,12 @@ pub(crate) fn build_function<'tcx>(
) -> Box<clean::Function> {
let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
// The generics need to be cleaned before the signature.
let mut generics =
clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
let mut generics = clean_ty_generics(
cx,
cx.tcx.generics_of(def_id),
cx.tcx.explicit_predicates_of(def_id),
def_id,
);
let bound_vars = clean_bound_vars(sig.bound_vars());

// At the time of writing early & late-bound params are stored separately in rustc,
Expand Down Expand Up @@ -317,7 +321,7 @@ fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
let predicates = cx.tcx.explicit_predicates_of(did);

clean::Enum {
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates, did),
variants: cx.tcx.adt_def(did).variants().iter().map(|v| clean_variant_def(v, cx)).collect(),
}
}
Expand All @@ -328,7 +332,7 @@ fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {

clean::Struct {
ctor_kind: variant.ctor_kind(),
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates, did),
fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(),
}
}
Expand All @@ -337,7 +341,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();

let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates, did);
let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect();
clean::Union { generics, fields }
}
Expand All @@ -354,7 +358,7 @@ fn build_type_alias(

Box::new(clean::TypeAlias {
type_,
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates, did),
inner_type,
item_type: None,
})
Expand Down Expand Up @@ -532,7 +536,7 @@ pub(crate) fn build_impl(
})
.map(|item| clean_impl_item(item, cx))
.collect::<Vec<_>>(),
clean_generics(impl_.generics, cx),
clean_generics(impl_.generics, cx, did),
),
None => (
tcx.associated_items(did)
Expand Down Expand Up @@ -560,7 +564,7 @@ pub(crate) fn build_impl(
.map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
clean::enter_impl_trait(cx, |cx| {
clean_ty_generics(cx, tcx.generics_of(did), predicates)
clean_ty_generics(cx, tcx.generics_of(did), predicates, did)
}),
),
};
Expand Down Expand Up @@ -718,8 +722,12 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
}

fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
let mut generics =
clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
let mut generics = clean_ty_generics(
cx,
cx.tcx.generics_of(def_id),
cx.tcx.explicit_predicates_of(def_id),
def_id,
);
clean::simplify::move_bounds_to_generic_parameters(&mut generics);

clean::Constant {
Expand Down
Loading

0 comments on commit 77b18b0

Please sign in to comment.