From b02a9688e8d5f7effcf3c1deb624e034fa106353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev> Date: Wed, 28 Feb 2024 08:13:29 +0100 Subject: [PATCH 1/3] rustdoc: pass owner item of generics to cleaning functions --- src/librustdoc/clean/auto_trait.rs | 2 + src/librustdoc/clean/blanket_impl.rs | 1 + src/librustdoc/clean/inline.rs | 30 ++++--- src/librustdoc/clean/mod.rs | 121 +++++++++++++++------------ 4 files changed, 91 insertions(+), 63 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index fbc2c3c5af459..ae756f2b1fc74 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -106,6 +106,7 @@ where self.cx, tcx.generics_of(item_def_id), ty::GenericPredicates::default(), + item_def_id, ); let params = raw_generics.params; @@ -456,6 +457,7 @@ where self.cx, tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id), + item_def_id, ); let mut generic_params = raw_generics.params; diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 47cfe651e319d..983d3be2d474c 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -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. diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 03f62f41a26f4..3486a986c88eb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -270,7 +270,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 } @@ -282,8 +282,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, @@ -315,7 +319,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(), } } @@ -326,7 +330,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(), } } @@ -335,7 +339,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 } } @@ -352,7 +356,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, }) @@ -530,7 +534,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) @@ -558,7 +562,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) }), ), }; @@ -716,8 +720,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 { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b32d3ad562d03..f4110428e5c27 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -631,22 +631,18 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { } pub(crate) fn clean_generics<'tcx>( - gens: &hir::Generics<'tcx>, + generics: &hir::Generics<'tcx>, cx: &mut DocContext<'tcx>, + _item_def_id: DefId, ) -> Generics { - let impl_trait_params = gens + let impl_trait_params = generics .params .iter() .filter(|param| is_impl_trait(param)) .map(|param| { - let param = clean_generic_param(cx, Some(gens), param); - match param.kind { - GenericParamDefKind::Lifetime { .. } => unreachable!(), - GenericParamDefKind::Type { ref bounds, .. } => { - cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec()); - } - GenericParamDefKind::Const { .. } => unreachable!(), - } + let param = clean_generic_param(cx, Some(generics), param); + let GenericParamDefKind::Type { bounds, .. } = ¶m.kind else { unreachable!() }; + cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec()); param }) .collect::<Vec<_>>(); @@ -654,7 +650,7 @@ pub(crate) fn clean_generics<'tcx>( let mut bound_predicates = FxIndexMap::default(); let mut region_predicates = FxIndexMap::default(); let mut eq_predicates = ThinVec::default(); - for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) { + for pred in generics.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) { match pred { WherePredicate::BoundPredicate { ty, bounds, bound_params } => { match bound_predicates.entry(ty) { @@ -697,15 +693,15 @@ pub(crate) fn clean_generics<'tcx>( } } - let mut params = ThinVec::with_capacity(gens.params.len()); + let mut params = ThinVec::with_capacity(generics.params.len()); // In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have // bounds in the where predicates. If so, we move their bounds into the where predicates // while also preventing duplicates. - for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let mut p = clean_generic_param(cx, Some(gens), p); - match &mut p.kind { - GenericParamDefKind::Lifetime { ref mut outlives } => { - if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) { + for param in generics.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { + let mut param = clean_generic_param(cx, Some(generics), param); + match &mut param.kind { + GenericParamDefKind::Lifetime { outlives } => { + if let Some(region_pred) = region_predicates.get_mut(&Lifetime(param.name)) { // We merge bounds in the `where` clause. for outlive in outlives.drain(..) { let outlive = GenericBound::Outlives(outlive); @@ -716,7 +712,7 @@ pub(crate) fn clean_generics<'tcx>( } } GenericParamDefKind::Type { bounds, synthetic: false, .. } => { - if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) { + if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(param.name)) { // We merge bounds in the `where` clause. for bound in bounds.drain(..) { if !bound_pred.0.contains(&bound) { @@ -729,7 +725,7 @@ pub(crate) fn clean_generics<'tcx>( // nothing to do here. } } - params.push(p); + params.push(param); } params.extend(impl_trait_params); @@ -754,8 +750,9 @@ pub(crate) fn clean_generics<'tcx>( fn clean_ty_generics<'tcx>( cx: &mut DocContext<'tcx>, - gens: &ty::Generics, - preds: ty::GenericPredicates<'tcx>, + generics: &ty::Generics, + predicates: ty::GenericPredicates<'tcx>, + _item_def_id: DefId, ) -> Generics { // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, // since `Clean for ty::Predicate` would consume them. @@ -764,7 +761,7 @@ fn clean_ty_generics<'tcx>( // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove // them. - let stripped_params = gens + let stripped_params = generics .params .iter() .filter_map(|param| match param.kind { @@ -790,7 +787,7 @@ fn clean_ty_generics<'tcx>( let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, ty::Binder<'_, ty::Term<'_>>)>>::default(); - let where_predicates = preds + let where_predicates = predicates .predicates .iter() .flat_map(|(pred, _)| { @@ -1040,7 +1037,13 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx), None => { - let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id)); + let mut func = clean_function( + cx, + item.owner_id.to_def_id(), + sig, + generics, + FunctionArgs::Body(body_id), + ); clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -1087,13 +1090,14 @@ enum FunctionArgs<'tcx> { fn clean_function<'tcx>( cx: &mut DocContext<'tcx>, + did: DefId, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, args: FunctionArgs<'tcx>, ) -> Box<Function> { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = clean_generics(generics, cx); + let generics = clean_generics(generics, cx, did); let args = match args { FunctionArgs::Body(body_id) => { clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id) @@ -1232,31 +1236,41 @@ fn clean_poly_trait_ref<'tcx>( } fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item { - let local_did = trait_item.owner_id.to_def_id(); - cx.with_param_env(local_did, |cx| { + let def_id = trait_item.owner_id.to_def_id(); + cx.with_param_env(def_id, |cx| { let inner = match trait_item.kind { hir::TraitItemKind::Const(ty, Some(default)) => { - let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let generics = + enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx, def_id)); AssocConstItem( generics, Box::new(clean_ty(ty, cx)), - ConstantKind::Local { def_id: local_did, body: default }, + ConstantKind::Local { def_id, body: default }, ) } hir::TraitItemKind::Const(ty, None) => { - let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let generics = + enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx, def_id)); TyAssocConstItem(generics, Box::new(clean_ty(ty, cx))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); + let m = + clean_function(cx, def_id, sig, trait_item.generics, FunctionArgs::Body(body)); MethodItem(m, None) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { - let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names)); + let m = clean_function( + cx, + def_id, + sig, + trait_item.generics, + FunctionArgs::Names(names), + ); TyMethodItem(m) } hir::TraitItemKind::Type(bounds, Some(default)) => { - let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let generics = + enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx, def_id)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); let item_type = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, default)), @@ -1275,12 +1289,13 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext ) } hir::TraitItemKind::Type(bounds, None) => { - let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let generics = + enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx, def_id)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); TyAssocTypeItem(generics, bounds) } }; - Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx) + Item::from_def_id_and_parts(def_id, Some(trait_item.ident.name), inner, cx) }) } @@ -1288,22 +1303,22 @@ pub(crate) fn clean_impl_item<'tcx>( impl_: &hir::ImplItem<'tcx>, cx: &mut DocContext<'tcx>, ) -> Item { - let local_did = impl_.owner_id.to_def_id(); - cx.with_param_env(local_did, |cx| { + let def_id = impl_.owner_id.to_def_id(); + cx.with_param_env(def_id, |cx| { let inner = match impl_.kind { hir::ImplItemKind::Const(ty, expr) => { - let generics = clean_generics(impl_.generics, cx); - let default = ConstantKind::Local { def_id: local_did, body: expr }; + let generics = clean_generics(impl_.generics, cx, def_id); + let default = ConstantKind::Local { def_id, body: expr }; AssocConstItem(generics, Box::new(clean_ty(ty, cx)), default) } hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); + let m = clean_function(cx, def_id, sig, impl_.generics, FunctionArgs::Body(body)); let defaultness = cx.tcx.defaultness(impl_.owner_id); MethodItem(m, Some(defaultness)) } hir::ImplItemKind::Type(hir_ty) => { let type_ = clean_ty(hir_ty, cx); - let generics = clean_generics(impl_.generics, cx); + let generics = clean_generics(impl_.generics, cx, def_id); let item_type = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, @@ -1322,7 +1337,7 @@ pub(crate) fn clean_impl_item<'tcx>( } }; - Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx) + Item::from_def_id_and_parts(def_id, Some(impl_.ident.name), inner, cx) }) } @@ -1344,6 +1359,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( cx, tcx.generics_of(assoc_item.def_id), tcx.explicit_predicates_of(assoc_item.def_id), + assoc_item.def_id, ); simplify::move_bounds_to_generic_parameters(&mut generics); @@ -1428,6 +1444,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, + assoc_item.def_id, ); simplify::move_bounds_to_generic_parameters(&mut generics); @@ -2731,12 +2748,12 @@ fn clean_maybe_renamed_item<'tcx>( } ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant { type_: Box::new(clean_ty(ty, cx)), - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), - generics: clean_generics(ty.generics, cx), + generics: clean_generics(ty.generics, cx, def_id), }), ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; @@ -2747,7 +2764,7 @@ fn clean_maybe_renamed_item<'tcx>( None, None, ); - let generics = clean_generics(generics, cx); + let generics = clean_generics(generics, cx, def_id); if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { *count -= 1; if *count == 0 { @@ -2777,19 +2794,19 @@ fn clean_maybe_renamed_item<'tcx>( } ItemKind::Enum(ref def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), }), ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias { - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), ItemKind::Union(ref variant_data, generics) => UnionItem(Union { - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Struct(ref variant_data, generics) => StructItem(Struct { ctor_kind: variant_data.ctor_kind(), - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), @@ -2813,7 +2830,7 @@ fn clean_maybe_renamed_item<'tcx>( TraitItem(Box::new(Trait { def_id, items, - generics: clean_generics(generics, cx), + generics: clean_generics(generics, cx, def_id), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), })) } @@ -2876,7 +2893,7 @@ fn clean_impl<'tcx>( let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| { let kind = ImplItem(Box::new(Impl { unsafety: impl_.unsafety, - generics: clean_generics(impl_.generics, cx), + generics: clean_generics(impl_.generics, cx, def_id.to_def_id()), trait_, for_, items, @@ -3086,7 +3103,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( hir::ForeignItemKind::Fn(decl, names, generics) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = clean_generics(generics, cx); + let generics = clean_generics(generics, cx, def_id); let args = clean_args_from_types_and_names(cx, decl.inputs, names); let decl = clean_fn_decl_with_args(cx, decl, None, args); (generics, decl) From 81217c53d564ca677d6087446c961e36986f616e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev> Date: Tue, 13 Feb 2024 06:09:13 +0100 Subject: [PATCH 2/3] rustdoc: change memory repr of generic params In anticipation of adding variance to them. --- src/librustdoc/clean/auto_trait.rs | 12 ++-- src/librustdoc/clean/mod.rs | 91 +++++++++++++----------------- src/librustdoc/clean/simplify.rs | 16 ++---- src/librustdoc/clean/types.rs | 60 ++++++++++++++++---- src/librustdoc/html/format.rs | 20 +++---- src/librustdoc/json/conversions.rs | 52 ++++------------- 6 files changed, 120 insertions(+), 131 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index ae756f2b1fc74..e7c964769a2ed 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -632,19 +632,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(); } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4110428e5c27..75d1e93d925b2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -507,32 +507,31 @@ fn clean_generic_param_def<'tcx>( ) -> GenericParamDef { let (name, kind) = match def.kind { ty::GenericParamDefKind::Lifetime => { - (def.name, GenericParamDefKind::Lifetime { outlives: ThinVec::new() }) + (def.name, LifetimeParam { outlives: ThinVec::new() }.into()) } ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { - let default = if has_default { - Some(clean_middle_ty( + let default = has_default.then(|| { + clean_middle_ty( ty::Binder::dummy(cx.tcx.type_of(def.def_id).instantiate_identity()), cx, Some(def.def_id), None, - )) - } else { - None - }; + ) + }); ( def.name, - GenericParamDefKind::Type { - bounds: ThinVec::new(), // These are filled in from the where-clauses. - default: default.map(Box::new), + TypeParam { + bounds: ThinVec::new(), // These are filled in from the where-clause. + default, synthetic, - }, + } + .into(), ) } ty::GenericParamDefKind::Const { has_default, is_host_effect } => ( def.name, - GenericParamDefKind::Const { - ty: Box::new(clean_middle_ty( + ConstParam { + ty: clean_middle_ty( ty::Binder::dummy( cx.tcx .type_of(def.def_id) @@ -542,15 +541,13 @@ fn clean_generic_param_def<'tcx>( cx, Some(def.def_id), None, - )), - default: match has_default { - true => Some(Box::new( - cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string(), - )), - false => None, - }, + ), + default: has_default.then(|| { + cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string() + }), is_host_effect, - }, + } + .into(), ), }; @@ -577,7 +574,7 @@ fn clean_generic_param<'tcx>( } else { ThinVec::new() }; - (param.name.ident().name, GenericParamDefKind::Lifetime { outlives }) + (param.name.ident().name, LifetimeParam { outlives }.into()) } hir::GenericParamKind::Type { ref default, synthetic } => { let bounds = if let Some(generics) = generics { @@ -592,21 +589,18 @@ fn clean_generic_param<'tcx>( }; ( param.name.ident().name, - GenericParamDefKind::Type { - bounds, - default: default.map(|t| clean_ty(t, cx)).map(Box::new), - synthetic, - }, + TypeParam { bounds, default: default.map(|t| clean_ty(t, cx)), synthetic }.into(), ) } hir::GenericParamKind::Const { ty, default, is_host_effect } => ( param.name.ident().name, - GenericParamDefKind::Const { - ty: Box::new(clean_ty(ty, cx)), + ConstParam { + ty: clean_ty(ty, cx), default: default - .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), + .map(|ct| ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string()), is_host_effect, - }, + } + .into(), ), }; @@ -641,8 +635,8 @@ pub(crate) fn clean_generics<'tcx>( .filter(|param| is_impl_trait(param)) .map(|param| { let param = clean_generic_param(cx, Some(generics), param); - let GenericParamDefKind::Type { bounds, .. } = ¶m.kind else { unreachable!() }; - cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec()); + let GenericParamDefKind::Type(ty_param) = ¶m.kind else { unreachable!() }; + cx.impl_trait_bounds.insert(param.def_id.into(), ty_param.bounds.to_vec()); param }) .collect::<Vec<_>>(); @@ -700,10 +694,10 @@ pub(crate) fn clean_generics<'tcx>( for param in generics.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { let mut param = clean_generic_param(cx, Some(generics), param); match &mut param.kind { - GenericParamDefKind::Lifetime { outlives } => { + GenericParamDefKind::Lifetime(lt_param) => { if let Some(region_pred) = region_predicates.get_mut(&Lifetime(param.name)) { // We merge bounds in the `where` clause. - for outlive in outlives.drain(..) { + for outlive in lt_param.outlives.drain(..) { let outlive = GenericBound::Outlives(outlive); if !region_pred.contains(&outlive) { region_pred.push(outlive); @@ -711,10 +705,10 @@ pub(crate) fn clean_generics<'tcx>( } } } - GenericParamDefKind::Type { bounds, synthetic: false, .. } => { + GenericParamDefKind::Type(ty_param) if !ty_param.synthetic => { if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(param.name)) { // We merge bounds in the `where` clause. - for bound in bounds.drain(..) { + for bound in ty_param.bounds.drain(..) { if !bound_pred.0.contains(&bound) { bound_pred.0.push(bound); } @@ -1062,17 +1056,15 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { match literal.kind { ast::LitKind::Int(a, _) => { - let gen = func.generics.params.remove(0); + let param = func.generics.params.remove(0); if let GenericParamDef { - name, - kind: GenericParamDefKind::Const { ty, .. }, - .. - } = gen + name, kind: GenericParamDefKind::Const(param), .. + } = param { - func.decl - .inputs - .values - .insert(a.get() as _, Argument { name, type_: *ty, is_const: true }); + func.decl.inputs.values.insert( + a.get() as _, + Argument { name, type_: param.ty, is_const: true }, + ); } else { panic!("unexpected non const in position {pos}"); } @@ -3160,11 +3152,8 @@ fn clean_bound_vars<'tcx>( Some(GenericParamDef { name, def_id, - kind: GenericParamDefKind::Type { - bounds: ThinVec::new(), - default: None, - synthetic: false, - }, + kind: TypeParam { bounds: ThinVec::new(), default: None, synthetic: false } + .into(), }) } // FIXME(non_lifetime_binders): Support higher-ranked const parameters. diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index c35fb9ec78875..910fbbcfaffbf 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -140,20 +140,16 @@ pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) let mut where_predicates = ThinVec::new(); for mut pred in generics.where_predicates.drain(..) { if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + && let Some(GenericParamDef { kind: GenericParamDefKind::Type(param), .. }) = + generics.params.iter_mut().find(|param| ¶m.name == arg) { - param_bounds.extend(bounds.drain(..)); + param.bounds.extend(bounds.drain(..)); } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Lifetime { outlives: param_bounds }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + && let Some(GenericParamDef { kind: GenericParamDefKind::Lifetime(param), .. }) = + generics.params.iter_mut().find(|param| ¶m.name == arg) { - param_bounds.extend(bounds.drain(..).map(|bound| match bound { + param.outlives.extend(bounds.drain(..).map(|bound| match bound { GenericBound::Outlives(lifetime) => lifetime, _ => unreachable!(), })); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c35baeb4cf587..978e0ddbf7790 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1325,10 +1325,9 @@ impl WherePredicate { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericParamDefKind { - Lifetime { outlives: ThinVec<Lifetime> }, - Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool }, - // Option<Box<String>> makes this type smaller than `Option<String>` would. - Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool }, + Lifetime(Box<LifetimeParam>), + Type(Box<TypeParam>), + Const(Box<ConstParam>), } impl GenericParamDefKind { @@ -1337,6 +1336,43 @@ impl GenericParamDefKind { } } +impl From<LifetimeParam> for GenericParamDefKind { + fn from(param: LifetimeParam) -> Self { + Self::Lifetime(Box::new(param)) + } +} + +impl From<TypeParam> for GenericParamDefKind { + fn from(param: TypeParam) -> Self { + Self::Type(Box::new(param)) + } +} + +impl From<ConstParam> for GenericParamDefKind { + fn from(param: ConstParam) -> Self { + Self::Const(Box::new(param)) + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub(crate) struct LifetimeParam { + pub(crate) outlives: ThinVec<Lifetime>, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub(crate) struct TypeParam { + pub(crate) bounds: ThinVec<GenericBound>, + pub(crate) default: Option<Type>, + pub(crate) synthetic: bool, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub(crate) struct ConstParam { + pub(crate) ty: Type, + pub(crate) default: Option<String>, + pub(crate) is_host_effect: bool, +} + #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct GenericParamDef { pub(crate) name: Symbol, @@ -1346,14 +1382,14 @@ pub(crate) struct GenericParamDef { impl GenericParamDef { pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self { - Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } } + Self { name, def_id, kind: LifetimeParam { outlives: ThinVec::new() }.into() } } pub(crate) fn is_synthetic_param(&self) -> bool { - match self.kind { - GenericParamDefKind::Lifetime { .. } => false, - GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect, - GenericParamDefKind::Type { synthetic, .. } => synthetic, + match &self.kind { + GenericParamDefKind::Lifetime(_) => false, + GenericParamDefKind::Const(param) => param.is_host_effect, + GenericParamDefKind::Type(param) => param.synthetic, } } @@ -1362,8 +1398,8 @@ impl GenericParamDef { } pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> { - match self.kind { - GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), + match &self.kind { + GenericParamDefKind::Type(param) => Some(¶m.bounds), _ => None, } } @@ -2561,7 +2597,7 @@ mod size_asserts { static_assert_size!(DocFragment, 32); static_assert_size!(GenericArg, 32); static_assert_size!(GenericArgs, 32); - static_assert_size!(GenericParamDef, 40); + static_assert_size!(GenericParamDef, 32); static_assert_size!(Generics, 16); static_assert_size!(Item, 56); static_assert_size!(ItemKind, 56); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index afd5eb42d019d..5629d8a0842ea 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -188,12 +188,12 @@ impl clean::GenericParamDef { cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { - clean::GenericParamDefKind::Lifetime { outlives } => { + clean::GenericParamDefKind::Lifetime(param) => { write!(f, "{}", self.name)?; - if !outlives.is_empty() { + if !param.outlives.is_empty() { f.write_str(": ")?; - for (i, lt) in outlives.iter().enumerate() { + for (i, lt) in param.outlives.iter().enumerate() { if i != 0 { f.write_str(" + ")?; } @@ -203,26 +203,26 @@ impl clean::GenericParamDef { Ok(()) } - clean::GenericParamDefKind::Type { bounds, default, .. } => { + clean::GenericParamDefKind::Type(param) => { f.write_str(self.name.as_str())?; - if !bounds.is_empty() { + if !param.bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(¶m.bounds, cx).fmt(f)?; } - if let Some(ref ty) = default { + if let Some(ref ty) = param.default { f.write_str(" = ")?; ty.print(cx).fmt(f)?; } Ok(()) } - clean::GenericParamDefKind::Const { ty, default, .. } => { + clean::GenericParamDefKind::Const(param) => { write!(f, "const {}: ", self.name)?; - ty.print(cx).fmt(f)?; + param.ty.print(cx).fmt(f)?; - if let Some(default) = default { + if let Some(default) = ¶m.default { f.write_str(" = ")?; if f.alternate() { write!(f, "{default}")?; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cb50a27326fe5..e47b415d39d10 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -453,18 +453,17 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { - Lifetime { outlives } => GenericParamDefKind::Lifetime { - outlives: outlives.into_iter().map(convert_lifetime).collect(), + Lifetime(param) => GenericParamDefKind::Lifetime { + outlives: param.outlives.into_iter().map(convert_lifetime).collect(), }, - Type { bounds, default, synthetic } => GenericParamDefKind::Type { - bounds: bounds.into_tcx(tcx), - default: default.map(|x| (*x).into_tcx(tcx)), - synthetic, - }, - Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), - default: default.map(|x| *x), + Type(param) => GenericParamDefKind::Type { + bounds: param.bounds.into_tcx(tcx), + default: param.default.map(|ty| ty.into_tcx(tcx)), + synthetic: param.synthetic, }, + Const(param) => { + GenericParamDefKind::Const { type_: param.ty.into_tcx(tcx), default: param.default } + } } } } @@ -476,38 +475,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { type_: ty.into_tcx(tcx), bounds: bounds.into_tcx(tcx), - generic_params: bound_params - .into_iter() - .map(|x| { - let name = x.name.to_string(); - let kind = match x.kind { - clean::GenericParamDefKind::Lifetime { outlives } => { - GenericParamDefKind::Lifetime { - outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(), - } - } - clean::GenericParamDefKind::Type { bounds, default, synthetic } => { - GenericParamDefKind::Type { - bounds: bounds - .into_iter() - .map(|bound| bound.into_tcx(tcx)) - .collect(), - default: default.map(|ty| (*ty).into_tcx(tcx)), - synthetic, - } - } - clean::GenericParamDefKind::Const { - ty, - default, - is_host_effect: _, - } => GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), - default: default.map(|d| *d), - }, - }; - GenericParamDef { name, kind } - }) - .collect(), + generic_params: bound_params.into_iter().map(|param| param.into_tcx(tcx)).collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { lifetime: convert_lifetime(lifetime), From 48f25fb2f00259041697d9f53efeb5ee29b5d806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev> Date: Wed, 28 Feb 2024 08:15:05 +0100 Subject: [PATCH 3/3] [wip] rustdoc: variances --- src/librustdoc/clean/auto_trait.rs | 4 +- src/librustdoc/clean/mod.rs | 117 +++++++++++++++++++++++------ src/librustdoc/clean/types.rs | 6 +- src/librustdoc/html/format.rs | 19 ++++- 4 files changed, 119 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index e7c964769a2ed..03dbb2338d927 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -106,7 +106,7 @@ where self.cx, tcx.generics_of(item_def_id), ty::GenericPredicates::default(), - item_def_id, + item_def_id, // FIXME: ofc its DefKind is not an impl confusing the variance compution ); let params = raw_generics.params; @@ -457,7 +457,7 @@ where self.cx, tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id), - item_def_id, + item_def_id, // FIXME: ofc its DefKind is not an impl confusing the variance compution ); let mut generic_params = raw_generics.params; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 75d1e93d925b2..49acabb6e538f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -322,7 +322,7 @@ fn clean_where_predicate<'tcx>( let bound_params = wbp .bound_generic_params .iter() - .map(|param| clean_generic_param(cx, None, param)) + .map(|param| clean_generic_param(cx, param, None, None)) .collect(); WherePredicate::BoundPredicate { ty: clean_ty(wbp.bounded_ty, cx), @@ -503,11 +503,12 @@ fn projection_to_path_segment<'tcx>( fn clean_generic_param_def<'tcx>( def: &ty::GenericParamDef, + variance: Option<ty::Variance>, cx: &mut DocContext<'tcx>, ) -> GenericParamDef { let (name, kind) = match def.kind { ty::GenericParamDefKind::Lifetime => { - (def.name, LifetimeParam { outlives: ThinVec::new() }.into()) + (def.name, LifetimeParam { variance, outlives: ThinVec::new() }.into()) } ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = has_default.then(|| { @@ -521,6 +522,7 @@ fn clean_generic_param_def<'tcx>( ( def.name, TypeParam { + variance, bounds: ThinVec::new(), // These are filled in from the where-clause. default, synthetic, @@ -556,8 +558,9 @@ fn clean_generic_param_def<'tcx>( fn clean_generic_param<'tcx>( cx: &mut DocContext<'tcx>, - generics: Option<&hir::Generics<'tcx>>, param: &hir::GenericParam<'tcx>, + variance: Option<ty::Variance>, + generics: Option<&hir::Generics<'tcx>>, ) -> GenericParamDef { let (name, kind) = match param.kind { hir::GenericParamKind::Lifetime { .. } => { @@ -574,7 +577,7 @@ fn clean_generic_param<'tcx>( } else { ThinVec::new() }; - (param.name.ident().name, LifetimeParam { outlives }.into()) + (param.name.ident().name, LifetimeParam { variance, outlives }.into()) } hir::GenericParamKind::Type { ref default, synthetic } => { let bounds = if let Some(generics) = generics { @@ -589,7 +592,13 @@ fn clean_generic_param<'tcx>( }; ( param.name.ident().name, - TypeParam { bounds, default: default.map(|t| clean_ty(t, cx)), synthetic }.into(), + TypeParam { + variance, + bounds, + default: default.map(|t| clean_ty(t, cx)), + synthetic, + } + .into(), ) } hir::GenericParamKind::Const { ty, default, is_host_effect } => ( @@ -627,14 +636,42 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { pub(crate) fn clean_generics<'tcx>( generics: &hir::Generics<'tcx>, cx: &mut DocContext<'tcx>, - _item_def_id: DefId, + item_def_id: DefId, ) -> Generics { + // FIXME(fmease): Instead of querying the defkind, we could instead let the caller make the decision + // NOTE: This would also fix us rendering variances in synthetic impls which use the + // DefId of the ADT. + // FIXME(fmease): Add DefKind::TyAlias if type_alias_is_lazy() + let def_kind = cx.tcx.def_kind(item_def_id); + let variances = if !generics.params.is_empty() + && let DefKind::Fn + | DefKind::AssocFn + | DefKind::Enum + | DefKind::Struct + | DefKind::Union + | DefKind::OpaqueTy = def_kind + { + let variances = cx.tcx.variances_of(item_def_id); + let generics = cx.tcx.generics_of(item_def_id); + + eprintln!("::: item={item_def_id:?} params={:?}", generics.params); + eprintln!("--> variances_raw={variances:?}"); + + Some((variances, generics)) + } else { + None + }; + let impl_trait_params = generics .params .iter() - .filter(|param| is_impl_trait(param)) - .map(|param| { - let param = clean_generic_param(cx, Some(generics), param); + .enumerate() + .filter(|(_, param)| is_impl_trait(param)) + .map(|(_index, param)| { + // FIXME: this isn't correct for AssocFn since the variances also contain the parent variances, cut them off + // let variance = variances.map(|variances| variances[index]); // FIXME(fmease): impl + let variance = None; + let param = clean_generic_param(cx, param, variance, Some(generics)); let GenericParamDefKind::Type(ty_param) = ¶m.kind else { unreachable!() }; cx.impl_trait_bounds.insert(param.def_id.into(), ty_param.bounds.to_vec()); param @@ -692,7 +729,12 @@ pub(crate) fn clean_generics<'tcx>( // bounds in the where predicates. If so, we move their bounds into the where predicates // while also preventing duplicates. for param in generics.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let mut param = clean_generic_param(cx, Some(generics), param); + let variance = variances.and_then(|(variances, generics)| { + let index = generics.param_def_id_to_index.get(¶m.def_id.to_def_id())?; + Some(variances[*index as usize]) + }); + let mut param = clean_generic_param(cx, param, variance, Some(generics)); + match &mut param.kind { GenericParamDefKind::Lifetime(lt_param) => { if let Some(region_pred) = region_predicates.get_mut(&Lifetime(param.name)) { @@ -746,8 +788,25 @@ fn clean_ty_generics<'tcx>( cx: &mut DocContext<'tcx>, generics: &ty::Generics, predicates: ty::GenericPredicates<'tcx>, - _item_def_id: DefId, + item_def_id: DefId, ) -> Generics { + // FIXME(fmease): Instead of querying the defkind, we could instead let the caller make the decision + // NOTE: This would also fix us rendering variances in synthetic impls which use the + // DefId of the ADT. + // FIXME(fmease): Add DefKind::TyAlias if type_alias_is_lazy() + let variances = if !generics.params.is_empty() + && let DefKind::Fn + | DefKind::AssocFn + | DefKind::Enum + | DefKind::Struct + | DefKind::Union + | DefKind::OpaqueTy = cx.tcx.def_kind(item_def_id) + { + Some(cx.tcx.variances_of(item_def_id)) + } else { + None + }; + // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, // since `Clean for ty::Predicate` would consume them. let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default(); @@ -758,22 +817,28 @@ fn clean_ty_generics<'tcx>( let stripped_params = generics .params .iter() - .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None, - ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)), + .filter(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(), ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name == kw::SelfUpper { assert_eq!(param.index, 0); - return None; + return false; } if synthetic { impl_trait.insert(param.index.into(), vec![]); - return None; + return false; } - Some(clean_generic_param_def(param, cx)) + true } - ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None, - ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), + ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect, + }) + .map(|param| { + // FIXME(fmease): We will probably handle AssocFn incorrectly since it has + // parent generics (we prob need to offset shit) + let variance = variances + .map(|variances| variances[generics.param_def_id_to_index[¶m.def_id] as usize]); + + clean_generic_param_def(param, variance, cx) }) .collect::<ThinVec<GenericParamDef>>(); @@ -1222,7 +1287,7 @@ fn clean_poly_trait_ref<'tcx>( .bound_generic_params .iter() .filter(|p| !is_elided_lifetime(p)) - .map(|x| clean_generic_param(cx, None, x)) + .map(|x| clean_generic_param(cx, x, None, None)) .collect(), } } @@ -2566,7 +2631,7 @@ fn clean_bare_fn_ty<'tcx>( .generic_params .iter() .filter(|p| !is_elided_lifetime(p)) - .map(|x| clean_generic_param(cx, None, x)) + .map(|x| clean_generic_param(cx, x, None, None)) // FIXME(fmease): variance? .collect(); let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names); let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args); @@ -3152,8 +3217,14 @@ fn clean_bound_vars<'tcx>( Some(GenericParamDef { name, def_id, - kind: TypeParam { bounds: ThinVec::new(), default: None, synthetic: false } - .into(), + // FIXME(fmease): higher-ranked generic params don't have a variance, right? + kind: TypeParam { + variance: None, + bounds: ThinVec::new(), + default: None, + synthetic: false, + } + .into(), }) } // FIXME(non_lifetime_binders): Support higher-ranked const parameters. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 978e0ddbf7790..2c324b6391eea 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1356,11 +1356,13 @@ impl From<ConstParam> for GenericParamDefKind { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct LifetimeParam { + pub(crate) variance: Option<ty::Variance>, pub(crate) outlives: ThinVec<Lifetime>, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct TypeParam { + pub(crate) variance: Option<ty::Variance>, pub(crate) bounds: ThinVec<GenericBound>, pub(crate) default: Option<Type>, pub(crate) synthetic: bool, @@ -1382,7 +1384,9 @@ pub(crate) struct GenericParamDef { impl GenericParamDef { pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self { - Self { name, def_id, kind: LifetimeParam { outlives: ThinVec::new() }.into() } + // FIXME(fmease): Don't use a fixed variance. + let param = LifetimeParam { variance: None, outlives: ThinVec::new() }; + Self { name, def_id, kind: param.into() } } pub(crate) fn is_synthetic_param(&self) -> bool { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5629d8a0842ea..52cbe10b5958f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -189,7 +189,10 @@ impl clean::GenericParamDef { ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { clean::GenericParamDefKind::Lifetime(param) => { - write!(f, "{}", self.name)?; + if let Some(variance) = param.variance { + f.write_str(print_variance(variance))?; + } + f.write_str(self.name.as_str())?; if !param.outlives.is_empty() { f.write_str(": ")?; @@ -204,6 +207,9 @@ impl clean::GenericParamDef { Ok(()) } clean::GenericParamDefKind::Type(param) => { + if let Some(variance) = param.variance { + f.write_str(print_variance(variance))?; + } f.write_str(self.name.as_str())?; if !param.bounds.is_empty() { @@ -1749,6 +1755,17 @@ impl clean::Term { } } +// FIXME(fmease): Do we need to care about alternate? +fn print_variance(variance: ty::Variance) -> &'static str { + match variance { + // ty::Variance::Covariant => "", + ty::Variance::Covariant => "<sub class=\"variance\">+</sub>", // FIXME: temporary + ty::Variance::Invariant => r#"<sub class="variance" title="invariant">∘</sub>"#, + ty::Variance::Contravariant => r#"<sub class="variance" title="contravariant">−</sub>"#, + ty::Variance::Bivariant => r#"<sub class="variance" title="bivariant">∗</sub>"#, + } +} + pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display { struct WithFormatter<F>(Cell<Option<F>>);