diff options
| author | Michael Goulet <michael@errs.io> | 2022-02-14 19:01:56 -0800 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-03-03 13:01:35 -0800 |
| commit | aefc0a223a0022a156be07b18feb45cd07e517e0 (patch) | |
| tree | 487a3f9fdb3f76ee623c7aecb9b5caa69eca3ee3 | |
| parent | ca6e06efba2201da6be9d48f3f922fbb4e90af5f (diff) | |
| download | rust-aefc0a223a0022a156be07b18feb45cd07e517e0.tar.gz rust-aefc0a223a0022a156be07b18feb45cd07e517e0.zip | |
make generic projection types print correctly
| -rw-r--r-- | src/librustdoc/clean/auto_trait.rs | 6 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 87 | ||||
| -rw-r--r-- | src/librustdoc/clean/simplify.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 16 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 16 | ||||
| -rw-r--r-- | src/librustdoc/json/conversions.rs | 11 | ||||
| -rw-r--r-- | src/rustdoc-json-types/lib.rs | 6 |
8 files changed, 107 insertions, 41 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index a3154d8f03b..62f3527525e 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -546,11 +546,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } WherePredicate::EqPredicate { lhs, rhs } => { match lhs { - Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { + Type::QPath { ref assoc, ref self_type, ref trait_, .. } => { let ty = &*self_type; let mut new_trait = trait_.clone(); - if self.is_fn_trait(trait_) && left_name == sym::Output { + if self.is_fn_trait(trait_) && assoc.name == sym::Output { ty_to_fn .entry(*ty.clone()) .and_modify(|e| { @@ -571,7 +571,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // to 'T: Iterator<Item=u8>' GenericArgs::AngleBracketed { ref mut bindings, .. } => { bindings.push(TypeBinding { - name: left_name, + assoc: *assoc.clone(), kind: TypeBindingKind::Equality { term: rhs }, }); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f0ae01f3803..2a32432d4e6 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -636,7 +636,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: g.where_predicates.retain(|pred| match pred { clean::WherePredicate::BoundPredicate { - ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. }, + ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, .. }, bounds, .. } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2864f69756b..fb88b9f7895 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -388,7 +388,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { let trait_ = lifted.trait_ref(cx.tcx).clean(cx); let self_type = self.self_ty().clean(cx); Type::QPath { - name: cx.tcx.associated_item(self.item_def_id).name, + assoc: Box::new(projection_to_path_segment(*self, cx)), self_def_id: self_type.def_id(&cx.cache), self_type: box self_type, trait_, @@ -396,6 +396,27 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { } } +fn projection_to_path_segment(ty: ty::ProjectionTy<'_>, cx: &mut DocContext<'_>) -> PathSegment { + let item = cx.tcx.associated_item(ty.item_def_id); + let generics = cx.tcx.generics_of(ty.item_def_id); + PathSegment { + name: item.name, + args: GenericArgs::AngleBracketed { + args: ty.substs[generics.parent_count..] + .iter() + .map(|ty| match ty.unpack() { + ty::subst::GenericArgKind::Lifetime(lt) => { + GenericArg::Lifetime(lt.clean(cx).unwrap()) + } + ty::subst::GenericArgKind::Type(ty) => GenericArg::Type(ty.clean(cx)), + ty::subst::GenericArgKind::Const(c) => GenericArg::Const(Box::new(c.clean(cx))), + }) + .collect(), + bindings: Default::default(), + }, + } +} + impl Clean<GenericParamDef> for ty::GenericParamDef { fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { @@ -601,8 +622,8 @@ fn clean_ty_generics( }) .collect::<Vec<GenericParamDef>>(); - // param index -> [(DefId of trait, associated type name, type)] - let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'_>)>>::default(); + // param index -> [(DefId of trait, associated type name and generics, type)] + let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>)>>::default(); let where_predicates = preds .predicates @@ -648,8 +669,9 @@ fn clean_ty_generics( let proj = projection .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term)); - if let Some(((_, trait_did, name), rhs)) = - proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) + if let Some(((_, trait_did, name), rhs)) = proj + .as_ref() + .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs))) { // FIXME(...): Remove this unwrap() impl_trait_proj.entry(param_idx).or_default().push(( @@ -985,7 +1007,7 @@ impl Clean<Item> for hir::TraitItem<'_> { TyMethodItem(t) } hir::TraitItemKind::Type(bounds, ref default) => { - let generics = self.generics.clean(cx); + let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); let default = default.map(|t| t.clean(cx)); AssocTypeItem(Box::new(generics), bounds, default) @@ -1136,6 +1158,27 @@ impl Clean<Item> for ty::AssocItem { ty::AssocKind::Type => { let my_name = self.name; + fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { + match (¶m.kind, arg) { + (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty))) + if *ty == param.name => + { + true + } + ( + GenericParamDefKind::Lifetime { .. }, + GenericArg::Lifetime(Lifetime(lt)), + ) if *lt == param.name => true, + (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => { + match &c.kind { + ConstantKind::TyConst { expr } => expr == param.name.as_str(), + _ => false, + } + } + _ => false, + } + } + if let ty::TraitContainer(_) = self.container { let bounds = tcx.explicit_item_bounds(self.def_id); let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; @@ -1147,10 +1190,10 @@ impl Clean<Item> for ty::AssocItem { .where_predicates .drain_filter(|pred| match *pred { WherePredicate::BoundPredicate { - ty: QPath { name, ref self_type, ref trait_, .. }, + ty: QPath { ref assoc, ref self_type, ref trait_, .. }, .. } => { - if name != my_name { + if assoc.name != my_name { return false; } if trait_.def_id() != self.container.id() { @@ -1267,7 +1310,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { }; register_res(cx, trait_.res); Type::QPath { - name: p.segments.last().expect("segments were empty").ident.name, + assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)), self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_type: box qself.clean(cx), trait_, @@ -1284,7 +1327,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { let trait_ = hir::Path { span, res, segments: &[] }.clean(cx); register_res(cx, trait_.res); Type::QPath { - name: segment.ident.name, + assoc: Box::new(segment.clean(cx)), self_def_id: res.opt_def_id(), self_type: box qself.clean(cx), trait_, @@ -1557,7 +1600,16 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { let mut bindings = vec![]; for pb in obj.projection_bounds() { bindings.push(TypeBinding { - name: cx.tcx.associated_item(pb.item_def_id()).name, + assoc: projection_to_path_segment( + pb.skip_binder() + .lift_to_tcx(cx.tcx) + .unwrap() + // HACK(compiler-errors): Doesn't actually matter what self + // type we put here, because we're only using the GAT's substs. + .with_self_ty(cx.tcx, cx.tcx.types.self_param) + .projection_ty, + cx, + ), kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) }, }); } @@ -1623,10 +1675,10 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { == trait_ref.skip_binder() { Some(TypeBinding { - name: cx - .tcx - .associated_item(proj.projection_ty.item_def_id) - .name, + assoc: projection_to_path_segment( + proj.projection_ty, + cx, + ), kind: TypeBindingKind::Equality { term: proj.term.clean(cx), }, @@ -2169,7 +2221,10 @@ fn clean_maybe_renamed_foreign_item( impl Clean<TypeBinding> for hir::TypeBinding<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding { - TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) } + TypeBinding { + assoc: PathSegment { name: self.ident.name, args: self.gen_args.clean(cx) }, + kind: self.kind.clean(cx), + } } } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index ea18d915deb..dd8e1132572 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -89,7 +89,7 @@ crate fn merge_bounds( cx: &clean::DocContext<'_>, bounds: &mut Vec<clean::GenericBound>, trait_did: DefId, - name: Symbol, + assoc: clean::PathSegment, rhs: &clean::Term, ) -> bool { !bounds.iter_mut().any(|b| { @@ -107,7 +107,7 @@ crate fn merge_bounds( match last.args { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { - name, + assoc: assoc.clone(), kind: clean::TypeBindingKind::Equality { term: rhs.clone() }, }); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3f40385f9b9..78928fb4059 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1397,7 +1397,7 @@ crate enum Type { /// A qualified path to an associated item: `<Type as Trait>::Name` QPath { - name: Symbol, + assoc: Box<PathSegment>, self_type: Box<Type>, /// FIXME: This is a hack that should be removed; see [this discussion][1]. /// @@ -1415,7 +1415,7 @@ crate enum Type { // `Type` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Type, 72); +rustc_data_structures::static_assert_size!(Type, 80); impl Type { /// When comparing types for equality, it can help to ignore `&` wrapping. @@ -1505,12 +1505,12 @@ impl Type { self.primitive_type().is_some() } - crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> { - let (self_, trait_, name) = match self { - QPath { self_type, trait_, name, .. } => (self_type, trait_, name), + crate fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { + let (self_, trait_, assoc) = match self { + QPath { self_type, trait_, assoc, .. } => (self_type, trait_, assoc), _ => return None, }; - Some((&self_, trait_.def_id(), *name)) + Some((&self_, trait_.def_id(), *assoc.clone())) } fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> { @@ -2018,7 +2018,7 @@ crate enum GenericArg { // `GenericArg` can occur many times in a single `Path`, so make sure it // doesn't increase in size unexpectedly. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(GenericArg, 80); +rustc_data_structures::static_assert_size!(GenericArg, 88); #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum GenericArgs { @@ -2256,7 +2256,7 @@ crate struct ProcMacro { /// `A: Send + Sync` in `Foo<A: Send + Sync>`). #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct TypeBinding { - crate name: Symbol, + crate assoc: PathSegment, crate kind: TypeBindingKind, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index c0115bfc6d4..78965712dfa 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -961,7 +961,7 @@ fn fmt_type<'cx>( write!(f, "impl {}", print_generic_bounds(bounds, cx)) } } - clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => { + clean::QPath { ref assoc, ref self_type, ref trait_, ref self_def_id } => { let should_show_cast = !trait_.segments.is_empty() && self_def_id .zip(Some(trait_.def_id())) @@ -994,14 +994,15 @@ fn fmt_type<'cx>( write!( f, "<a class=\"associatedtype\" href=\"{url}#{shortty}.{name}\" \ - title=\"type {path}::{name}\">{name}</a>", + title=\"type {path}::{name}\">{name}</a>{args}", url = url, shortty = ItemType::AssocType, - name = name, + name = assoc.name, path = join_with_double_colon(path), + args = assoc.args.print(cx), )?; } - _ => write!(f, "{}", name)?, + _ => write!(f, "{}{:#}", assoc.name, assoc.args.print(cx))?, } Ok(()) } @@ -1457,7 +1458,12 @@ impl clean::TypeBinding { cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { - f.write_str(self.name.as_str())?; + f.write_str(self.assoc.name.as_str())?; + if f.alternate() { + write!(f, "{:#}", self.assoc.args.print(cx))?; + } else { + write!(f, "{}", self.assoc.args.print(cx))?; + } match self.kind { clean::TypeBindingKind::Equality { ref term } => { if f.alternate() { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index da92e682fe8..4358dc8980f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -154,7 +154,11 @@ impl FromWithTcx<clean::Constant> for Constant { impl FromWithTcx<clean::TypeBinding> for TypeBinding { fn from_tcx(binding: clean::TypeBinding, tcx: TyCtxt<'_>) -> Self { - TypeBinding { name: binding.name.to_string(), binding: binding.kind.into_tcx(tcx) } + TypeBinding { + name: binding.assoc.name.to_string(), + args: binding.assoc.args.into_tcx(tcx), + binding: binding.kind.into_tcx(tcx), + } } } @@ -445,11 +449,12 @@ impl FromWithTcx<clean::Type> for Type { mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, - QPath { name, self_type, trait_, .. } => { + QPath { assoc, self_type, trait_, .. } => { // FIXME: should `trait_` be a clean::Path equivalent in JSON? let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx); Type::QualifiedPath { - name: name.to_string(), + name: assoc.name.to_string(), + args: Box::new(assoc.args.clone().into_tcx(tcx)), self_type: Box::new((*self_type).into_tcx(tcx)), trait_: Box::new(trait_), } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index dfaec6991a4..40b0de44829 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 11; +pub const FORMAT_VERSION: u32 = 12; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -145,6 +145,7 @@ pub struct Constant { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TypeBinding { pub name: String, + pub args: GenericArgs, pub binding: TypeBindingKind, } @@ -233,9 +234,7 @@ pub enum ItemEnum { default: Option<String>, }, AssocType { - /// generics and `where` clause generics: Generics, - /// e.g. `: Sized` bounds: Vec<GenericBound>, /// e.g. `type X = usize;` default: Option<Type>, @@ -435,6 +434,7 @@ pub enum Type { /// `<Type as Trait>::Name` or associated types like `T::Item` where `T: Iterator` QualifiedPath { name: String, + args: Box<GenericArgs>, self_type: Box<Type>, #[serde(rename = "trait")] trait_: Box<Type>, |
