Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rustdoc-Json: Document HRTB's on DynTrait #99787

Merged
merged 5 commits into from
Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/etc/check_missing_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def check_type(ty):
for bound in binding["binding"]["constraint"]:
check_generic_bound(bound)
elif "parenthesized" in args:
for ty in args["parenthesized"]["inputs"]:
check_type(ty)
for input_ty in args["parenthesized"]["inputs"]:
check_type(input_ty)
if args["parenthesized"]["output"]:
check_type(args["parenthesized"]["output"])
if not valid_id(ty["inner"]["id"]):
Expand Down
120 changes: 59 additions & 61 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ where
}
}

impl<I, T, U> FromWithTcx<I> for Vec<U>
where
I: IntoIterator<Item = T>,
U: FromWithTcx<T>,
{
fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
f.into_iter().map(|x| x.into_tcx(tcx)).collect()
}
}

pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
#[rustfmt::skip]
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
Expand All @@ -130,11 +140,11 @@ impl FromWithTcx<clean::GenericArgs> for GenericArgs {
use clean::GenericArgs::*;
match args {
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
args: args.into_vec().into_tcx(tcx),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be doing the same thing but instead of creating one vector, it creates two. Did I miss something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no nevermind. But then I wonder why the into_vec is needed at all...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it’s not a Vec. It’s a boxed slice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably it could skip the into_vec because of the impl for IntoIterator right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like @camelid said. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

args is a Box<[GenericArg]>, which doesn't impl IntoIterator, but Vec does and the conversion is zero cost. I guess you could impl <T, U: FromWithTcx<T>> FromWithTcx<Box<[T]>> for Vec<U>, but I don't think thats worth it as it only comes up twice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh strange. Well if it doesn't work don't worry about it then.

bindings: bindings.into_tcx(tcx),
},
Parenthesized { inputs, output } => GenericArgs::Parenthesized {
inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
inputs: inputs.into_vec().into_tcx(tcx),
output: output.map(|a| (*a).into_tcx(tcx)),
},
}
Expand All @@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
use clean::GenericArg::*;
match arg {
Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
Type(t) => GenericArg::Type(t.into_tcx(tcx)),
Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
Infer => GenericArg::Infer,
Expand Down Expand Up @@ -177,9 +187,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
use clean::TypeBindingKind::*;
match kind {
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
}
Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
}
}
}
Expand Down Expand Up @@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignTypeItem => ItemEnum::ForeignType,
Expand All @@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
}
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: (*g).into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: b.into_tcx(tcx),
default: None,
},
AssocTypeItem(t, b) => ItemEnum::AssocType {
generics: t.generics.into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: b.into_tcx(tcx),
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
},
// `convert_item` early returns `None` for stripped items and keywords.
Expand Down Expand Up @@ -347,15 +355,15 @@ fn convert_abi(a: RustcAbi) -> Abi {
}
}

fn convert_lifetime(l: clean::Lifetime) -> String {
l.0.to_string()
}

impl FromWithTcx<clean::Generics> for Generics {
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
Generics {
params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
where_predicates: generics
.where_predicates
.into_iter()
.map(|x| x.into_tcx(tcx))
.collect(),
params: generics.params.into_tcx(tcx),
where_predicates: generics.where_predicates.into_tcx(tcx),
}
}
}
Expand All @@ -374,10 +382,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
use clean::GenericParamDefKind::*;
match kind {
Lifetime { outlives } => GenericParamDefKind::Lifetime {
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
outlives: outlives.into_iter().map(convert_lifetime).collect(),
},
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
default: default.map(|x| (*x).into_tcx(tcx)),
synthetic,
},
Expand All @@ -395,7 +403,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
match predicate {
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
type_: ty.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
generic_params: bound_params
.into_iter()
.map(|x| GenericParamDef {
Expand All @@ -405,8 +413,8 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
.collect(),
},
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
lifetime: lifetime.0.to_string(),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
lifetime: convert_lifetime(lifetime),
bounds: bounds.into_tcx(tcx),
},
EqPredicate { lhs, rhs } => {
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
Expand All @@ -424,11 +432,11 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generic_params: generic_params.into_tcx(tcx),
modifier: from_trait_bound_modifier(modifier),
}
}
Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
}
}
}
Expand All @@ -447,8 +455,8 @@ pub(crate) fn from_trait_bound_modifier(
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
QPath, RawPointer, Slice, Tuple,
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple,
};

match ty {
Expand All @@ -458,40 +466,24 @@ impl FromWithTcx<clean::Type> for Type {
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
DynTrait(mut bounds, lt) => {
let first_trait = bounds.remove(0).trait_;

Type::ResolvedPath {
name: first_trait.whole_name(),
id: from_item_id(first_trait.def_id().into(), tcx),
args: first_trait
.segments
.last()
.map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: bounds
.into_iter()
.map(|t| {
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
})
.chain(lt.map(clean::GenericBound::Outlives))
.map(|bound| bound.into_tcx(tcx))
.collect(),
}
}
clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
lifetime: lt.map(convert_lifetime),
traits: bounds.into_tcx(tcx),
}),
Generic(s) => Type::Generic(s.to_string()),
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()),
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
lifetime: lifetime.map(|l| l.0.to_string()),
lifetime: lifetime.map(convert_lifetime),
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
Expand Down Expand Up @@ -528,7 +520,7 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
async_: false,
abi: convert_abi(abi),
},
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generic_params: generic_params.into_tcx(tcx),
decl: decl.into_tcx(tcx),
}
}
Expand Down Expand Up @@ -562,16 +554,28 @@ impl FromWithTcx<clean::Trait> for Trait {
is_unsafe,
items: ids(items, tcx),
generics: generics.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
bounds: bounds.into_tcx(tcx),
implementations: Vec::new(), // Added in JsonRenderer::item
}
}
}

impl FromWithTcx<Box<clean::Impl>> for Impl {
fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self {
impl FromWithTcx<clean::PolyTrait> for PolyTrait {
fn from_tcx(
clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
tcx: TyCtxt<'_>,
) -> Self {
PolyTrait {
trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we keep it in Path form rather than allowing it to be any type. (Type definition needs to be updated too.)

Suggested change
trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
trait_: trait_.into_tcx(tcx),

Copy link
Member Author

@aDotInTheVoid aDotInTheVoid Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't yet have a ResolvedPath type in the json output, so I think that should be done in a followup change, as theirs a couple of other places we'd also want to use it (

// FIXME: should `trait_` be a clean::Path equivalent in JSON?
,
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, makes sense to hold off then.

generic_params: generic_params.into_tcx(tcx),
}
}
}

impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_;
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
Expand Down Expand Up @@ -730,10 +734,7 @@ impl FromWithTcx<Box<clean::Typedef>> for Typedef {

impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
OpaqueTy {
bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generics: opaque.generics.into_tcx(tcx),
}
OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
}
}

Expand All @@ -749,10 +750,7 @@ impl FromWithTcx<clean::Static> for Static {

impl FromWithTcx<clean::TraitAlias> for TraitAlias {
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
TraitAlias {
generics: alias.generics.into_tcx(tcx),
params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
}
TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
}
}

Expand Down
38 changes: 34 additions & 4 deletions src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};

/// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 16;
pub const FORMAT_VERSION: u32 = 17;

/// 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
Expand Down Expand Up @@ -115,6 +115,35 @@ pub enum Visibility {
},
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DynTrait {
/// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
pub traits: Vec<PolyTrait>,
/// The lifetime of the whole dyn object
/// ```text
/// dyn Debug + 'static
/// ^^^^^^^
/// |
/// this part
/// ```
pub lifetime: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
/// A trait and potential HRTBs
pub struct PolyTrait {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure what the best name for this is. The compiler seems to use PolyTrait everywhere for this, but I don't think it's ever used outside that context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know what it means ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Trait with possible HRTB params

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't hesitate to add doc comments to explain what it stands for. Always appreciated.

#[serde(rename = "trait")]
pub trait_: Type,
camelid marked this conversation as resolved.
Show resolved Hide resolved
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```text
/// dyn for<'a> Fn() -> &'a i32"
/// ^^^^^^^
/// |
/// this part
/// ```
pub generic_params: Vec<GenericParamDef>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GenericArgs {
Expand Down Expand Up @@ -395,7 +424,7 @@ pub enum WherePredicate {
type_: Type,
bounds: Vec<GenericBound>,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// where for<'a> &'a T: Iterator,"
/// ^^^^^^^
/// |
Expand All @@ -420,7 +449,7 @@ pub enum GenericBound {
#[serde(rename = "trait")]
trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
/// ^^^^^^^^^^^
/// |
Expand Down Expand Up @@ -458,6 +487,7 @@ pub enum Type {
args: Option<Box<GenericArgs>>,
param_names: Vec<GenericBound>,
},
DynTrait(DynTrait),
/// Parameterized types
Generic(String),
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
Expand Down Expand Up @@ -505,7 +535,7 @@ pub enum Type {
pub struct FunctionPointer {
pub decl: FnDecl,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain
/// ```text
/// for<'c> fn(val: &'c i32) -> i32
/// ^^^^^^^
/// |
Expand Down
Loading