rustdoc: Introduce new DynTrait
type for better representation of trait objects
This commit is contained in:
parent
1f65f56461
commit
4ea27484c9
9 changed files with 117 additions and 116 deletions
|
@ -353,12 +353,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
let (poly_trait, output) =
|
||||
(data.0.as_ref().expect("as_ref failed").clone(), data.1.as_ref().cloned());
|
||||
let new_ty = match poly_trait.trait_ {
|
||||
Type::ResolvedPath {
|
||||
ref path,
|
||||
ref param_names,
|
||||
ref did,
|
||||
ref is_generic,
|
||||
} => {
|
||||
Type::ResolvedPath { ref path, ref did, ref is_generic } => {
|
||||
let mut new_path = path.clone();
|
||||
let last_segment =
|
||||
new_path.segments.pop().expect("segments were empty");
|
||||
|
@ -395,7 +390,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
|
||||
Type::ResolvedPath {
|
||||
path: new_path,
|
||||
param_names: param_names.clone(),
|
||||
did: *did,
|
||||
is_generic: *is_generic,
|
||||
}
|
||||
|
@ -570,7 +564,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
match **trait_ {
|
||||
Type::ResolvedPath {
|
||||
path: ref trait_path,
|
||||
ref param_names,
|
||||
ref did,
|
||||
ref is_generic,
|
||||
} => {
|
||||
|
@ -617,7 +610,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
PolyTrait {
|
||||
trait_: Type::ResolvedPath {
|
||||
path: new_trait_path,
|
||||
param_names: param_names.clone(),
|
||||
did: *did,
|
||||
is_generic: *is_generic,
|
||||
},
|
||||
|
|
|
@ -180,7 +180,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
|
|||
|
||||
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
|
||||
|
||||
ResolvedPath { path, param_names: None, did: trait_ref.def_id, is_generic: false }
|
||||
ResolvedPath { path, did: trait_ref.def_id, is_generic: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,30 +1378,9 @@ impl Clean<Type> for hir::Ty<'_> {
|
|||
}
|
||||
TyKind::Path(_) => clean_qpath(&self, cx),
|
||||
TyKind::TraitObject(ref bounds, ref lifetime, _) => {
|
||||
let cleaned = bounds[0].clean(cx);
|
||||
match cleaned.trait_ {
|
||||
ResolvedPath { path, param_names: None, did, is_generic, .. } => {
|
||||
let mut bounds: Vec<self::GenericBound> = bounds[1..]
|
||||
.iter()
|
||||
.map(|bound| {
|
||||
self::GenericBound::TraitBound(
|
||||
bound.clean(cx),
|
||||
hir::TraitBoundModifier::None,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
if !lifetime.is_elided() {
|
||||
bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
|
||||
}
|
||||
ResolvedPath {
|
||||
path,
|
||||
param_names: Some((bounds, cleaned.generic_params)),
|
||||
did,
|
||||
is_generic,
|
||||
}
|
||||
}
|
||||
_ => Infer, // shouldn't happen
|
||||
}
|
||||
let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
|
||||
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
|
||||
DynTrait(bounds, lifetime)
|
||||
}
|
||||
TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
|
||||
TyKind::Infer | TyKind::Err => Infer,
|
||||
|
@ -1484,7 +1463,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
};
|
||||
inline::record_extern_fqn(cx, did, kind);
|
||||
let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
|
||||
ResolvedPath { path, param_names: None, did, is_generic: false }
|
||||
ResolvedPath { path, did, is_generic: false }
|
||||
}
|
||||
ty::Foreign(did) => {
|
||||
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
|
||||
|
@ -1496,7 +1475,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
vec![],
|
||||
InternalSubsts::empty(),
|
||||
);
|
||||
ResolvedPath { path, param_names: None, did, is_generic: false }
|
||||
ResolvedPath { path, did, is_generic: false }
|
||||
}
|
||||
ty::Dynamic(ref obj, ref reg) => {
|
||||
// HACK: pick the first `did` as the `did` of the trait object. Someone
|
||||
|
@ -1514,28 +1493,19 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
|
||||
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
||||
|
||||
let mut param_names = vec![];
|
||||
if let Some(b) = reg.clean(cx) {
|
||||
param_names.push(GenericBound::Outlives(b));
|
||||
}
|
||||
let lifetime = reg.clean(cx);
|
||||
let mut bounds = vec![];
|
||||
|
||||
for did in dids {
|
||||
let empty = cx.tcx.intern_substs(&[]);
|
||||
let path =
|
||||
external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
|
||||
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
||||
let bound = GenericBound::TraitBound(
|
||||
PolyTrait {
|
||||
trait_: ResolvedPath {
|
||||
path,
|
||||
param_names: None,
|
||||
did,
|
||||
is_generic: false,
|
||||
},
|
||||
let bound = PolyTrait {
|
||||
trait_: ResolvedPath { path, did, is_generic: false },
|
||||
generic_params: Vec::new(),
|
||||
},
|
||||
hir::TraitBoundModifier::None,
|
||||
);
|
||||
param_names.push(bound);
|
||||
};
|
||||
bounds.push(bound);
|
||||
}
|
||||
|
||||
let mut bindings = vec![];
|
||||
|
@ -1548,12 +1518,15 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
|
||||
let path =
|
||||
external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
|
||||
ResolvedPath {
|
||||
path,
|
||||
param_names: Some((param_names, vec![])),
|
||||
did,
|
||||
is_generic: false,
|
||||
}
|
||||
bounds.insert(
|
||||
0,
|
||||
PolyTrait {
|
||||
trait_: ResolvedPath { path, did, is_generic: false },
|
||||
generic_params: Vec::new(),
|
||||
},
|
||||
);
|
||||
|
||||
DynTrait(bounds, lifetime)
|
||||
}
|
||||
ty::Tuple(ref t) => {
|
||||
Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
|
||||
|
@ -2257,14 +2230,9 @@ impl From<GenericBound> for SimpleBound {
|
|||
match bound.clone() {
|
||||
GenericBound::Outlives(l) => SimpleBound::Outlives(l),
|
||||
GenericBound::TraitBound(t, mod_) => match t.trait_ {
|
||||
Type::ResolvedPath { path, param_names, .. } => SimpleBound::TraitBound(
|
||||
path.segments,
|
||||
param_names.map_or_else(Vec::new, |(v, _)| {
|
||||
v.iter().map(|p| SimpleBound::from(p.clone())).collect()
|
||||
}),
|
||||
t.generic_params,
|
||||
mod_,
|
||||
),
|
||||
Type::ResolvedPath { path, .. } => {
|
||||
SimpleBound::TraitBound(path.segments, Vec::new(), t.generic_params, mod_)
|
||||
}
|
||||
_ => panic!("Unexpected bound {:?}", bound),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1141,7 +1141,7 @@ impl GenericBound {
|
|||
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
||||
GenericBound::TraitBound(
|
||||
PolyTrait {
|
||||
trait_: ResolvedPath { path, param_names: None, did, is_generic: false },
|
||||
trait_: ResolvedPath { path, did, is_generic: false },
|
||||
generic_params: Vec::new(),
|
||||
},
|
||||
hir::TraitBoundModifier::Maybe,
|
||||
|
@ -1407,13 +1407,12 @@ crate enum Type {
|
|||
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
|
||||
ResolvedPath {
|
||||
path: Path,
|
||||
/// If `param_names` is `Some`, this path is a trait object and the Vecs repsresent
|
||||
/// `(generic bounds, generic parameters)`
|
||||
param_names: Option<(Vec<GenericBound>, Vec<GenericParamDef>)>,
|
||||
did: DefId,
|
||||
/// `true` if is a `T::Name` path for associated types.
|
||||
is_generic: bool,
|
||||
},
|
||||
/// `dyn for<'a> Trait<'a> + Send + 'static`
|
||||
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
|
||||
/// For parameterized types, so the consumer of the JSON don't go
|
||||
/// looking for types which don't exist anywhere.
|
||||
Generic(Symbol),
|
||||
|
@ -1600,6 +1599,7 @@ impl Type {
|
|||
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
|
||||
let t: PrimitiveType = match *self {
|
||||
ResolvedPath { did, .. } => return Some(did.into()),
|
||||
DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache),
|
||||
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
|
||||
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
|
||||
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder;
|
|||
use crate::clean::blanket_impl::BlanketImplFinder;
|
||||
use crate::clean::{
|
||||
inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
|
||||
Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
|
||||
Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
|
||||
};
|
||||
use crate::core::DocContext;
|
||||
use crate::formats::item_type::ItemType;
|
||||
|
@ -163,8 +163,18 @@ pub(super) fn external_path(
|
|||
|
||||
crate fn strip_type(ty: Type) -> Type {
|
||||
match ty {
|
||||
Type::ResolvedPath { path, param_names, did, is_generic } => {
|
||||
Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
|
||||
Type::ResolvedPath { path, did, is_generic } => {
|
||||
Type::ResolvedPath { path: strip_path(&path), did, is_generic }
|
||||
}
|
||||
Type::DynTrait(mut bounds, lt) => {
|
||||
let first = bounds.remove(0);
|
||||
let stripped_trait = strip_type(first.trait_);
|
||||
|
||||
bounds.insert(
|
||||
0,
|
||||
PolyTrait { trait_: stripped_trait, generic_params: first.generic_params },
|
||||
);
|
||||
Type::DynTrait(bounds, lt)
|
||||
}
|
||||
Type::Tuple(inner_tys) => {
|
||||
Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
|
||||
|
@ -431,7 +441,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty
|
|||
_ => false,
|
||||
};
|
||||
let did = register_res(cx, path.res);
|
||||
ResolvedPath { path, param_names: None, did, is_generic }
|
||||
ResolvedPath { path, did, is_generic }
|
||||
}
|
||||
|
||||
crate fn get_auto_trait_and_blanket_impls(
|
||||
|
|
|
@ -402,6 +402,15 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
|||
self.cache.parent_stack.push(did);
|
||||
true
|
||||
}
|
||||
clean::DynTrait(ref bounds, _)
|
||||
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
|
||||
if let Some(did) = bounds[0].trait_.def_id() {
|
||||
self.cache.parent_stack.push(did);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ref t => {
|
||||
let prim_did = t
|
||||
.primitive_type()
|
||||
|
@ -432,6 +441,12 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
|||
| clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
|
||||
dids.insert(did);
|
||||
}
|
||||
clean::DynTrait(ref bounds, _)
|
||||
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
|
||||
if let Some(did) = bounds[0].trait_.def_id() {
|
||||
dids.insert(did);
|
||||
}
|
||||
}
|
||||
ref t => {
|
||||
let did = t
|
||||
.primitive_type()
|
||||
|
|
|
@ -646,18 +646,24 @@ fn primitive_link(
|
|||
|
||||
/// Helper to render type parameters
|
||||
fn tybounds<'a, 'tcx: 'a>(
|
||||
param_names: Option<&'a Vec<clean::GenericBound>>,
|
||||
bounds: &'a Vec<clean::PolyTrait>,
|
||||
lt: &'a Option<clean::Lifetime>,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl fmt::Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| match param_names {
|
||||
Some(params) => {
|
||||
for param in params {
|
||||
display_fn(move |f| {
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, " + ")?;
|
||||
fmt::Display::fmt(¶m.print(cx), f)?;
|
||||
}
|
||||
|
||||
fmt::Display::fmt(&bound.print(cx), f)?;
|
||||
}
|
||||
|
||||
if let Some(lt) = lt {
|
||||
write!(f, " + ")?;
|
||||
fmt::Display::fmt(<.print(), f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
None => Ok(()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -694,32 +700,13 @@ fn fmt_type<'cx>(
|
|||
|
||||
match *t {
|
||||
clean::Generic(name) => write!(f, "{}", name),
|
||||
clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
|
||||
let generic_params = param_names.as_ref().map(|(_, x)| x);
|
||||
let param_names = param_names.as_ref().map(|(x, _)| x);
|
||||
|
||||
if let Some(generic_params) = generic_params {
|
||||
f.write_str("dyn ")?;
|
||||
|
||||
if !generic_params.is_empty() {
|
||||
if f.alternate() {
|
||||
write!(
|
||||
f,
|
||||
"for<{:#}> ",
|
||||
comma_sep(generic_params.iter().map(|g| g.print(cx)))
|
||||
)?;
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"for<{}> ",
|
||||
comma_sep(generic_params.iter().map(|g| g.print(cx)))
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
clean::ResolvedPath { did, ref path, is_generic } => {
|
||||
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
||||
resolved_path(f, did, path, is_generic, use_absolute, cx)?;
|
||||
fmt::Display::fmt(&tybounds(param_names, cx), f)
|
||||
resolved_path(f, did, path, is_generic, use_absolute, cx)
|
||||
}
|
||||
clean::DynTrait(ref bounds, ref lt) => {
|
||||
f.write_str("dyn ")?;
|
||||
fmt::Display::fmt(&tybounds(bounds, lt, cx), f)
|
||||
}
|
||||
clean::Infer => write!(f, "_"),
|
||||
clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
|
||||
|
@ -854,7 +841,9 @@ fn fmt_type<'cx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
clean::ResolvedPath { param_names: Some((ref v, _)), .. } if !v.is_empty() => {
|
||||
clean::DynTrait(ref bounds, ref trait_lt)
|
||||
if bounds.len() > 1 || trait_lt.is_some() =>
|
||||
{
|
||||
write!(f, "{}{}{}(", amp, lt, m)?;
|
||||
fmt_type(&ty, f, use_absolute, cx)?;
|
||||
write!(f, ")")
|
||||
|
@ -915,7 +904,7 @@ fn fmt_type<'cx>(
|
|||
// the ugliness comes from inlining across crates where
|
||||
// everything comes in as a fully resolved QPath (hard to
|
||||
// look at).
|
||||
box clean::ResolvedPath { did, ref param_names, .. } => {
|
||||
box clean::ResolvedPath { did, .. } => {
|
||||
match href(did.into(), cx) {
|
||||
Some((ref url, _, ref path)) if !f.alternate() => {
|
||||
write!(
|
||||
|
@ -930,9 +919,6 @@ fn fmt_type<'cx>(
|
|||
}
|
||||
_ => write!(f, "{}", name)?,
|
||||
}
|
||||
|
||||
// FIXME: `param_names` are not rendered, and this seems bad?
|
||||
drop(param_names);
|
||||
Ok(())
|
||||
}
|
||||
_ => write!(f, "{}", name),
|
||||
|
|
|
@ -233,6 +233,7 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
|
|||
});
|
||||
Some(path_segment.name)
|
||||
}
|
||||
clean::DynTrait(ref bounds, _) => get_index_type_name(&bounds[0].trait_, accept_generic),
|
||||
clean::Generic(s) if accept_generic => Some(s),
|
||||
clean::Primitive(ref p) => Some(p.as_sym()),
|
||||
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
|
||||
|
|
|
@ -373,14 +373,35 @@ impl FromWithTcx<clean::Type> for Type {
|
|||
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::Type::*;
|
||||
match ty {
|
||||
ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
|
||||
ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath {
|
||||
name: path.whole_name(),
|
||||
id: from_def_id(did.into()),
|
||||
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
|
||||
param_names: param_names
|
||||
.map(|(v, _)| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
|
||||
.unwrap_or_default(),
|
||||
param_names: Vec::new(),
|
||||
},
|
||||
DynTrait(mut bounds, lt) => {
|
||||
let (path, id) = match bounds.remove(0).trait_ {
|
||||
ResolvedPath { path, did, .. } => (path, did),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Type::ResolvedPath {
|
||||
name: path.whole_name(),
|
||||
id: from_def_id(id.into()),
|
||||
args: path
|
||||
.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.into_iter().map(|lt| clean::GenericBound::Outlives(lt)))
|
||||
.map(|bound| bound.into_tcx(tcx))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
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))),
|
||||
|
|
|
@ -51,3 +51,11 @@ pub trait B<'x> {}
|
|||
|
||||
// @has - '//code[@class="in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
|
||||
impl<'a> B<'a> for dyn for<'b> Trait<'b> {}
|
||||
|
||||
// @has foo/struct.Bar.html
|
||||
// @has - '//span[@id="structfield.bar"]' "bar: &'a (dyn for<'b> Trait<'b> + Unpin)"
|
||||
// @has - '//span[@id="structfield.baz"]' "baz: &'a (dyn Unpin + for<'b> Trait<'b>)"
|
||||
pub struct Bar<'a> {
|
||||
pub bar: &'a (dyn for<'b> Trait<'b> + Unpin),
|
||||
pub baz: &'a (dyn Unpin + for<'b> Trait<'b>),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue