1
Fork 0

Auto merge of #88379 - camelid:cleanup-clean, r=jyn514

rustdoc: Cleanup various `clean` types

Cleanup various `clean` types.
This commit is contained in:
bors 2021-10-09 19:05:08 +00:00
commit a8f2463c68
15 changed files with 416 additions and 515 deletions

View file

@ -118,7 +118,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
span: Span::dummy(), span: Span::dummy(),
unsafety: hir::Unsafety::Normal, unsafety: hir::Unsafety::Normal,
generics: new_generics, generics: new_generics,
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), trait_: Some(trait_ref.clean(self.cx)),
for_: ty.clean(self.cx), for_: ty.clean(self.cx),
items: Vec::new(), items: Vec::new(),
negative_polarity, negative_polarity,
@ -166,16 +166,16 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
.clone() .clone()
} }
// This method calculates two things: Lifetime constraints of the form 'a: 'b, /// This method calculates two things: Lifetime constraints of the form `'a: 'b`,
// and region constraints of the form ReVar: 'a /// and region constraints of the form `RegionVid: 'a`
// ///
// This is essentially a simplified version of lexical_region_resolve. However, /// This is essentially a simplified version of lexical_region_resolve. However,
// handle_lifetimes determines what *needs be* true in order for an impl to hold. /// handle_lifetimes determines what *needs be* true in order for an impl to hold.
// lexical_region_resolve, along with much of the rest of the compiler, is concerned /// lexical_region_resolve, along with much of the rest of the compiler, is concerned
// with determining if a given set up constraints/predicates *are* met, given some /// with determining if a given set up constraints/predicates *are* met, given some
// starting conditions (e.g., user-provided code). For this reason, it's easier /// starting conditions (e.g., user-provided code). For this reason, it's easier
// to perform the calculations we need on our own, rather than trying to make /// to perform the calculations we need on our own, rather than trying to make
// existing inference/solver code do what we want. /// existing inference/solver code do what we want.
fn handle_lifetimes<'cx>( fn handle_lifetimes<'cx>(
regions: &RegionConstraintData<'cx>, regions: &RegionConstraintData<'cx>,
names_map: &FxHashMap<Symbol, Lifetime>, names_map: &FxHashMap<Symbol, Lifetime>,
@ -353,48 +353,35 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
if let Some(data) = ty_to_fn.get(&ty) { if let Some(data) = ty_to_fn.get(&ty) {
let (poly_trait, output) = let (poly_trait, output) =
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
let new_ty = match poly_trait.trait_ { let mut new_path = poly_trait.trait_.clone();
Type::ResolvedPath { ref path, ref did } => { let last_segment = new_path.segments.pop().expect("segments were empty");
let mut new_path = path.clone();
let last_segment =
new_path.segments.pop().expect("segments were empty");
let (old_input, old_output) = match last_segment.args { let (old_input, old_output) = match last_segment.args {
GenericArgs::AngleBracketed { args, .. } => { GenericArgs::AngleBracketed { args, .. } => {
let types = args let types = args
.iter() .iter()
.filter_map(|arg| match arg { .filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty.clone()), GenericArg::Type(ty) => Some(ty.clone()),
_ => None, _ => None,
}) })
.collect(); .collect();
(types, None) (types, None)
}
GenericArgs::Parenthesized { inputs, output, .. } => {
(inputs, output)
}
};
if old_output.is_some() && old_output != output {
panic!(
"Output mismatch for {:?} {:?} {:?}",
ty, old_output, data.1
);
}
let new_params =
GenericArgs::Parenthesized { inputs: old_input, output };
new_path
.segments
.push(PathSegment { name: last_segment.name, args: new_params });
Type::ResolvedPath { path: new_path, did: *did }
} }
_ => panic!("Unexpected data: {:?}, {:?}", ty, data), GenericArgs::Parenthesized { inputs, output } => (inputs, output),
}; };
if old_output.is_some() && old_output != output {
panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1);
}
let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
new_path
.segments
.push(PathSegment { name: last_segment.name, args: new_params });
bounds.insert(GenericBound::TraitBound( bounds.insert(GenericBound::TraitBound(
PolyTrait { trait_: new_ty, generic_params: poly_trait.generic_params }, PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params },
hir::TraitBoundModifier::None, hir::TraitBoundModifier::None,
)); ));
} }
@ -423,15 +410,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
.collect() .collect()
} }
// Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for
// display on the docs page. Cleaning the Predicates produces sub-optimal `WherePredicate`s, /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s,
// so we fix them up: /// so we fix them up:
// ///
// * Multiple bounds for the same type are coalesced into one: e.g., 'T: Copy', 'T: Debug' /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug`
// becomes 'T: Copy + Debug' /// becomes `T: Copy + Debug`
// * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), <T as Fn::Output> = /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), <T as Fn::Output> =
// K', we use the dedicated syntax 'T: Fn() -> K' /// K`, we use the dedicated syntax `T: Fn() -> K`
// * We explicitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type
fn param_env_to_generics( fn param_env_to_generics(
&mut self, &mut self,
item_def_id: DefId, item_def_id: DefId,
@ -476,7 +463,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
let mut has_sized = FxHashSet::default(); let mut has_sized = FxHashSet::default();
let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
let mut ty_to_traits: FxHashMap<Type, FxHashSet<Type>> = Default::default(); let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default(); let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
@ -511,11 +498,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
if b.is_sized_bound(self.cx) { if b.is_sized_bound(self.cx) {
has_sized.insert(ty.clone()); has_sized.insert(ty.clone());
} else if !b } else if !b
.get_trait_type() .get_trait_path()
.and_then(|t| { .and_then(|trait_| {
ty_to_traits ty_to_traits
.get(&ty) .get(&ty)
.map(|bounds| bounds.contains(&strip_type(t.clone()))) .map(|bounds| bounds.contains(&strip_path_generics(trait_.clone())))
}) })
.unwrap_or(false) .unwrap_or(false)
{ {
@ -532,7 +519,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
// that we don't end up with duplicate bounds (e.g., for<'b, 'b>) // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
for_generics.extend(p.generic_params.clone()); for_generics.extend(p.generic_params.clone());
p.generic_params = for_generics.into_iter().collect(); p.generic_params = for_generics.into_iter().collect();
self.is_fn_ty(&p.trait_) self.is_fn_trait(&p.trait_)
} }
_ => false, _ => false,
}; };
@ -558,78 +545,59 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
match lhs { match lhs {
Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
let ty = &*self_type; let ty = &*self_type;
match **trait_ { let mut new_trait = trait_.clone();
Type::ResolvedPath { path: ref trait_path, ref did } => {
let mut new_trait_path = trait_path.clone();
if self.is_fn_ty(trait_) && left_name == sym::Output { if self.is_fn_trait(trait_) && left_name == sym::Output {
ty_to_fn ty_to_fn
.entry(*ty.clone()) .entry(*ty.clone())
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
.or_insert((None, Some(rhs))); .or_insert((None, Some(rhs)));
continue; continue;
}
let args = &mut new_trait_path
.segments
.last_mut()
.expect("segments were empty")
.args;
match args {
// Convert something like '<T as Iterator::Item> = u8'
// to 'T: Iterator<Item=u8>'
GenericArgs::AngleBracketed {
ref mut bindings, ..
} => {
bindings.push(TypeBinding {
name: left_name,
kind: TypeBindingKind::Equality { ty: rhs },
});
}
GenericArgs::Parenthesized { .. } => {
existing_predicates.push(WherePredicate::EqPredicate {
lhs: lhs.clone(),
rhs,
});
continue; // If something other than a Fn ends up
// with parenthesis, leave it alone
}
}
let bounds = ty_to_bounds.entry(*ty.clone()).or_default();
bounds.insert(GenericBound::TraitBound(
PolyTrait {
trait_: Type::ResolvedPath {
path: new_trait_path,
did: *did,
},
generic_params: Vec::new(),
},
hir::TraitBoundModifier::None,
));
// Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
// that we don't see a
// duplicate bound like `T: Iterator + Iterator<Item=u8>`
// on the docs page.
bounds.remove(&GenericBound::TraitBound(
PolyTrait {
trait_: *trait_.clone(),
generic_params: Vec::new(),
},
hir::TraitBoundModifier::None,
));
// Avoid creating any new duplicate bounds later in the outer
// loop
ty_to_traits
.entry(*ty.clone())
.or_default()
.insert(*trait_.clone());
}
_ => panic!("Unexpected trait {:?} for {:?}", trait_, item_def_id),
} }
let args = &mut new_trait
.segments
.last_mut()
.expect("segments were empty")
.args;
match args {
// Convert something like '<T as Iterator::Item> = u8'
// to 'T: Iterator<Item=u8>'
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding {
name: left_name,
kind: TypeBindingKind::Equality { ty: rhs },
});
}
GenericArgs::Parenthesized { .. } => {
existing_predicates.push(WherePredicate::EqPredicate {
lhs: lhs.clone(),
rhs,
});
continue; // If something other than a Fn ends up
// with parenthesis, leave it alone
}
}
let bounds = ty_to_bounds.entry(*ty.clone()).or_default();
bounds.insert(GenericBound::TraitBound(
PolyTrait { trait_: new_trait, generic_params: Vec::new() },
hir::TraitBoundModifier::None,
));
// Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
// that we don't see a
// duplicate bound like `T: Iterator + Iterator<Item=u8>`
// on the docs page.
bounds.remove(&GenericBound::TraitBound(
PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() },
hir::TraitBoundModifier::None,
));
// Avoid creating any new duplicate bounds later in the outer
// loop
ty_to_traits.entry(*ty.clone()).or_default().insert(trait_.clone());
} }
_ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id),
} }
@ -664,11 +632,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
Generics { params: generic_params, where_predicates: existing_predicates } Generics { params: generic_params, where_predicates: existing_predicates }
} }
// Ensure that the predicates are in a consistent order. The precise /// Ensure that the predicates are in a consistent order. The precise
// ordering doesn't actually matter, but it's important that /// ordering doesn't actually matter, but it's important that
// a given set of predicates always appears in the same order - /// a given set of predicates always appears in the same order -
// both for visual consistency between 'rustdoc' runs, and to /// both for visual consistency between 'rustdoc' runs, and to
// make writing tests much easier /// make writing tests much easier
#[inline] #[inline]
fn sort_where_predicates(&self, mut predicates: &mut Vec<WherePredicate>) { fn sort_where_predicates(&self, mut predicates: &mut Vec<WherePredicate>) {
// We should never have identical bounds - and if we do, // We should never have identical bounds - and if we do,
@ -677,11 +645,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
self.unstable_debug_sort(&mut predicates); self.unstable_debug_sort(&mut predicates);
} }
// Ensure that the bounds are in a consistent order. The precise /// Ensure that the bounds are in a consistent order. The precise
// ordering doesn't actually matter, but it's important that /// ordering doesn't actually matter, but it's important that
// a given set of bounds always appears in the same order - /// a given set of bounds always appears in the same order -
// both for visual consistency between 'rustdoc' runs, and to /// both for visual consistency between 'rustdoc' runs, and to
// make writing tests much easier /// make writing tests much easier
#[inline] #[inline]
fn sort_where_bounds(&self, mut bounds: &mut Vec<GenericBound>) { fn sort_where_bounds(&self, mut bounds: &mut Vec<GenericBound>) {
// We should never have identical bounds - and if we do, // We should never have identical bounds - and if we do,
@ -690,47 +658,43 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
self.unstable_debug_sort(&mut bounds); self.unstable_debug_sort(&mut bounds);
} }
// This might look horrendously hacky, but it's actually not that bad. /// This might look horrendously hacky, but it's actually not that bad.
// ///
// For performance reasons, we use several different FxHashMaps /// For performance reasons, we use several different FxHashMaps
// in the process of computing the final set of where predicates. /// in the process of computing the final set of where predicates.
// However, the iteration order of a HashMap is completely unspecified. /// However, the iteration order of a HashMap is completely unspecified.
// In fact, the iteration of an FxHashMap can even vary between platforms, /// In fact, the iteration of an FxHashMap can even vary between platforms,
// since FxHasher has different behavior for 32-bit and 64-bit platforms. /// since FxHasher has different behavior for 32-bit and 64-bit platforms.
// ///
// Obviously, it's extremely undesirable for documentation rendering /// Obviously, it's extremely undesirable for documentation rendering
// to be dependent on the platform it's run on. Apart from being confusing /// to be dependent on the platform it's run on. Apart from being confusing
// to end users, it makes writing tests much more difficult, as predicates /// to end users, it makes writing tests much more difficult, as predicates
// can appear in any order in the final result. /// can appear in any order in the final result.
// ///
// To solve this problem, we sort WherePredicates and GenericBounds /// To solve this problem, we sort WherePredicates and GenericBounds
// by their Debug string. The thing to keep in mind is that we don't really /// by their Debug string. The thing to keep in mind is that we don't really
// care what the final order is - we're synthesizing an impl or bound /// care what the final order is - we're synthesizing an impl or bound
// ourselves, so any order can be considered equally valid. By sorting the /// ourselves, so any order can be considered equally valid. By sorting the
// predicates and bounds, however, we ensure that for a given codebase, all /// predicates and bounds, however, we ensure that for a given codebase, all
// auto-trait impls always render in exactly the same way. /// auto-trait impls always render in exactly the same way.
// ///
// Using the Debug implementation for sorting prevents us from needing to /// Using the Debug implementation for sorting prevents us from needing to
// write quite a bit of almost entirely useless code (e.g., how should two /// write quite a bit of almost entirely useless code (e.g., how should two
// Types be sorted relative to each other). It also allows us to solve the /// Types be sorted relative to each other). It also allows us to solve the
// problem for both WherePredicates and GenericBounds at the same time. This /// problem for both WherePredicates and GenericBounds at the same time. This
// approach is probably somewhat slower, but the small number of items /// approach is probably somewhat slower, but the small number of items
// involved (impls rarely have more than a few bounds) means that it /// involved (impls rarely have more than a few bounds) means that it
// shouldn't matter in practice. /// shouldn't matter in practice.
fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) { fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) {
vec.sort_by_cached_key(|x| format!("{:?}", x)) vec.sort_by_cached_key(|x| format!("{:?}", x))
} }
fn is_fn_ty(&self, ty: &Type) -> bool { fn is_fn_trait(&self, path: &Path) -> bool {
let tcx = self.cx.tcx; let tcx = self.cx.tcx;
match ty { let did = path.def_id();
&Type::ResolvedPath { did, .. } => { did == tcx.require_lang_item(LangItem::Fn, None)
did == tcx.require_lang_item(LangItem::Fn, None) || did == tcx.require_lang_item(LangItem::FnMut, None)
|| did == tcx.require_lang_item(LangItem::FnMut, None) || did == tcx.require_lang_item(LangItem::FnOnce, None)
|| did == tcx.require_lang_item(LangItem::FnOnce, None)
}
_ => false,
}
} }
} }
@ -741,7 +705,7 @@ fn region_name(region: Region<'_>) -> Option<Symbol> {
} }
} }
// Replaces all ReVars in a type with ty::Region's, using the provided map /// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map.
struct RegionReplacer<'a, 'tcx> { struct RegionReplacer<'a, 'tcx> {
vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>, vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View file

@ -115,7 +115,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
.clean(self.cx), .clean(self.cx),
// FIXME(eddyb) compute both `trait_` and `for_` from // FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate. // the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), trait_: Some(trait_ref.clean(self.cx)),
for_: ty.clean(self.cx), for_: ty.clean(self.cx),
items: self items: self
.cx .cx

View file

@ -446,20 +446,26 @@ crate fn build_impl(
), ),
}; };
let polarity = tcx.impl_polarity(did); let polarity = tcx.impl_polarity(did);
let trait_ = associated_trait.clean(cx).map(|bound| match bound { let trait_ = associated_trait.clean(cx);
clean::GenericBound::TraitBound(polyt, _) => polyt.trait_, if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
clean::GenericBound::Outlives(..) => unreachable!(),
});
if trait_.def_id() == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret); super::build_deref_target_impls(cx, &trait_items, ret);
} }
// Return if the trait itself or any types of the generic parameters are doc(hidden). // Return if the trait itself or any types of the generic parameters are doc(hidden).
let mut stack: Vec<&Type> = trait_.iter().collect(); let mut stack: Vec<&Type> = vec![&for_];
stack.push(&for_);
if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
return;
}
}
if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
stack.extend(generics);
}
while let Some(ty) = stack.pop() { while let Some(ty) = stack.pop() {
if let Some(did) = ty.def_id() { if let Some(did) = ty.def_id() {
if cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
return; return;
} }
} }
@ -468,14 +474,14 @@ crate fn build_impl(
} }
} }
if let Some(trait_did) = trait_.def_id() { if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
record_extern_trait(cx, trait_did); record_extern_trait(cx, did);
} }
let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
trace!("merged_attrs={:?}", merged_attrs); trace!("merged_attrs={:?}", merged_attrs);
trace!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id());
ret.push(clean::Item::from_def_id_and_attrs_and_parts( ret.push(clean::Item::from_def_id_and_attrs_and_parts(
did, did,
None, None,
@ -526,7 +532,6 @@ fn build_module(
item.ident.name, item.ident.name,
clean::ImportSource { clean::ImportSource {
path: clean::Path { path: clean::Path {
global: false,
res, res,
segments: vec![clean::PathSegment { segments: vec![clean::PathSegment {
name: prim_ty.as_sym(), name: prim_ty.as_sym(),
@ -621,11 +626,10 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
ref mut bounds, ref mut bounds,
.. ..
} if *s == kw::SelfUpper => { } if *s == kw::SelfUpper => {
bounds.retain(|bound| match *bound { bounds.retain(|bound| match bound {
clean::GenericBound::TraitBound( clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. }, trait_.def_id() != trait_did
_, }
) => did != trait_did,
_ => true, _ => true,
}); });
} }
@ -633,18 +637,12 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
} }
} }
g.where_predicates.retain(|pred| match *pred { g.where_predicates.retain(|pred| match pred {
clean::WherePredicate::BoundPredicate { clean::WherePredicate::BoundPredicate {
ty: ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. },
clean::QPath { bounds,
self_type: box clean::Generic(ref s),
trait_: box clean::ResolvedPath { did, .. },
name: ref _name,
..
},
ref bounds,
.. ..
} => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
_ => true, _ => true,
}); });
g g

View file

@ -152,8 +152,8 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
} }
} }
impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) { impl Clean<Path> for (ty::TraitRef<'_>, &[TypeBinding]) {
fn clean(&self, cx: &mut DocContext<'_>) -> Type { fn clean(&self, cx: &mut DocContext<'_>) -> Path {
let (trait_ref, bounds) = *self; let (trait_ref, bounds) = *self;
let kind = cx.tcx.def_kind(trait_ref.def_id).into(); let kind = cx.tcx.def_kind(trait_ref.def_id).into();
if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
@ -168,16 +168,13 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
ResolvedPath { path, did: trait_ref.def_id } path
} }
} }
impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> { impl Clean<Path> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound { fn clean(&self, cx: &mut DocContext<'_>) -> Path {
GenericBound::TraitBound( (*self, &[][..]).clean(cx)
PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] },
hir::TraitBoundModifier::None,
)
} }
} }
@ -384,16 +381,13 @@ impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type { fn clean(&self, cx: &mut DocContext<'_>) -> Type {
let lifted = self.lift_to_tcx(cx.tcx).unwrap(); let lifted = self.lift_to_tcx(cx.tcx).unwrap();
let trait_ = match lifted.trait_ref(cx.tcx).clean(cx) { let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
GenericBound::TraitBound(t, _) => t.trait_,
GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
};
let self_type = self.self_ty().clean(cx); let self_type = self.self_ty().clean(cx);
Type::QPath { Type::QPath {
name: cx.tcx.associated_item(self.item_def_id).ident.name, name: cx.tcx.associated_item(self.item_def_id).ident.name,
self_def_id: self_type.def_id(), self_def_id: self_type.def_id(),
self_type: box self_type, self_type: box self_type,
trait_: box trait_, trait_,
} }
} }
} }
@ -896,10 +890,11 @@ impl Clean<bool> for hir::IsAuto {
} }
} }
impl Clean<Type> for hir::TraitRef<'_> { impl Clean<Path> for hir::TraitRef<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type { fn clean(&self, cx: &mut DocContext<'_>) -> Path {
let path = self.path.clean(cx); let path = self.path.clean(cx);
resolve_type(cx, path) register_res(cx, path.res);
path
} }
} }
@ -1105,9 +1100,8 @@ impl Clean<Item> for ty::AssocItem {
if *name != my_name { if *name != my_name {
return None; return None;
} }
match **trait_ { if trait_.def_id() != self.container.id() {
ResolvedPath { did, .. } if did == self.container.id() => {} return None;
_ => return None,
} }
match **self_type { match **self_type {
Generic(ref s) if *s == kw::SelfUpper => {} Generic(ref s) if *s == kw::SelfUpper => {}
@ -1273,19 +1267,18 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
return normalized_value.clean(cx); return normalized_value.clean(cx);
} }
let segments = if p.is_global() { &p.segments[1..] } else { &p.segments }; let trait_segments = &p.segments[..p.segments.len() - 1];
let trait_segments = &segments[..segments.len() - 1];
let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id(); let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
let trait_path = self::Path { let trait_ = self::Path {
global: p.is_global(),
res: Res::Def(DefKind::Trait, trait_def), res: Res::Def(DefKind::Trait, trait_def),
segments: trait_segments.clean(cx), segments: trait_segments.clean(cx),
}; };
register_res(cx, trait_.res);
Type::QPath { Type::QPath {
name: p.segments.last().expect("segments were empty").ident.name, name: p.segments.last().expect("segments were empty").ident.name,
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
self_type: box qself.clean(cx), self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path), trait_,
} }
} }
hir::QPath::TypeRelative(ref qself, ref segment) => { hir::QPath::TypeRelative(ref qself, ref segment) => {
@ -1296,12 +1289,13 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
ty::Error(_) => return Type::Infer, ty::Error(_) => return Type::Infer,
_ => bug!("clean: expected associated type, found `{:?}`", ty), _ => bug!("clean: expected associated type, found `{:?}`", ty),
}; };
let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
register_res(cx, trait_.res);
Type::QPath { Type::QPath {
name: segment.ident.name, name: segment.ident.name,
self_def_id: res.opt_def_id(), self_def_id: res.opt_def_id(),
self_type: box qself.clean(cx), self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path), trait_,
} }
} }
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
@ -1470,10 +1464,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
let empty = cx.tcx.intern_substs(&[]); let empty = cx.tcx.intern_substs(&[]);
let path = external_path(cx, did, false, vec![], empty); let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait); inline::record_extern_fqn(cx, did, ItemType::Trait);
let bound = PolyTrait { let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
trait_: ResolvedPath { path, did },
generic_params: Vec::new(),
};
bounds.push(bound); bounds.push(bound);
} }
@ -1486,10 +1477,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
} }
let path = external_path(cx, did, false, bindings, substs); let path = external_path(cx, did, false, bindings, substs);
bounds.insert( bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
0,
PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() },
);
DynTrait(bounds, lifetime) DynTrait(bounds, lifetime)
} }
@ -1728,11 +1716,7 @@ impl Clean<Variant> for hir::VariantData<'_> {
impl Clean<Path> for hir::Path<'_> { impl Clean<Path> for hir::Path<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Path { fn clean(&self, cx: &mut DocContext<'_>) -> Path {
Path { Path { res: self.res, segments: self.segments.clean(cx) }
global: self.is_global(),
res: self.res,
segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
}
} }
} }
@ -1898,7 +1882,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
// If this impl block is an implementation of the Deref trait, then we // If this impl block is an implementation of the Deref trait, then we
// need to try inlining the target's inherent impl blocks as well. // need to try inlining the target's inherent impl blocks as well.
if trait_.def_id() == tcx.lang_items().deref_trait() { if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
build_deref_target_impls(cx, &items, &mut ret); build_deref_target_impls(cx, &items, &mut ret);
} }
@ -1907,7 +1891,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
_ => None, _ => None,
}); });
let mut make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| { let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Impl { let kind = ImplItem(Impl {
span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx), span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
unsafety: impl_.unsafety, unsafety: impl_.unsafety,

View file

@ -99,17 +99,13 @@ crate fn merge_bounds(
clean::GenericBound::TraitBound(ref mut tr, _) => tr, clean::GenericBound::TraitBound(ref mut tr, _) => tr,
clean::GenericBound::Outlives(..) => return false, clean::GenericBound::Outlives(..) => return false,
}; };
let (did, path) = match trait_ref.trait_ {
clean::ResolvedPath { did, ref mut path, .. } => (did, path),
_ => return false,
};
// If this QPath's trait `trait_did` is the same as, or a supertrait // If this QPath's trait `trait_did` is the same as, or a supertrait
// of, the bound's trait `did` then we can keep going, otherwise // of, the bound's trait `did` then we can keep going, otherwise
// this is just a plain old equality bound. // this is just a plain old equality bound.
if !trait_is_same_or_supertrait(cx, did, trait_did) { if !trait_is_same_or_supertrait(cx, trait_ref.trait_.def_id(), trait_did) {
return false; return false;
} }
let last = path.segments.last_mut().expect("segments were empty"); let last = trait_ref.trait_.segments.last_mut().expect("segments were empty");
match last.args { match last.args {
PP::AngleBracketed { ref mut bindings, .. } => { PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding { bindings.push(clean::TypeBinding {

View file

@ -120,8 +120,7 @@ crate struct Crate {
crate module: Item, crate module: Item,
crate externs: Vec<ExternalCrate>, crate externs: Vec<ExternalCrate>,
crate primitives: ThinVec<(DefId, PrimitiveType)>, crate primitives: ThinVec<(DefId, PrimitiveType)>,
// These are later on moved into `CACHEKEY`, leaving the map empty. /// Only here so that they can be filtered through the rustdoc passes.
// Only here so that they can be filtered through the rustdoc passes.
crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>, crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
crate collapsed: bool, crate collapsed: bool,
} }
@ -1147,7 +1146,7 @@ impl GenericBound {
let path = external_path(cx, did, false, vec![], empty); let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait); inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound( GenericBound::TraitBound(
PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, PolyTrait { trait_: path, generic_params: Vec::new() },
hir::TraitBoundModifier::Maybe, hir::TraitBoundModifier::Maybe,
) )
} }
@ -1155,7 +1154,7 @@ impl GenericBound {
crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
use rustc_hir::TraitBoundModifier as TBM; use rustc_hir::TraitBoundModifier as TBM;
if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
if trait_.def_id() == cx.tcx.lang_items().sized_trait() { if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() {
return true; return true;
} }
} }
@ -1169,7 +1168,7 @@ impl GenericBound {
None None
} }
crate fn get_trait_type(&self) -> Option<Type> { crate fn get_trait_path(&self) -> Option<Path> {
if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
Some(trait_.clone()) Some(trait_.clone())
} else { } else {
@ -1401,53 +1400,53 @@ crate struct TraitAlias {
/// A trait reference, which may have higher ranked lifetimes. /// A trait reference, which may have higher ranked lifetimes.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate struct PolyTrait { crate struct PolyTrait {
crate trait_: Type, crate trait_: Path,
crate generic_params: Vec<GenericParamDef>, crate generic_params: Vec<GenericParamDef>,
} }
/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original /// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
/// importantly, it does not preserve mutability or boxes.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate enum Type { crate enum Type {
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`). /// A named type, which could be a trait.
ResolvedPath { ///
path: Path, /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
did: DefId, ResolvedPath { path: Path, did: DefId },
}, /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
/// `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>), DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// For parameterized types, so the consumer of the JSON don't go /// A type parameter.
/// looking for types which don't exist anywhere.
Generic(Symbol), Generic(Symbol),
/// Primitives are the fixed-size numeric types (plus int/usize/float), char, /// A primitive (aka, builtin) type.
/// arrays, slices, and tuples.
Primitive(PrimitiveType), Primitive(PrimitiveType),
/// `extern "ABI" fn` /// A function pointer: `extern "ABI" fn(...) -> ...`
BareFunction(Box<BareFunctionDecl>), BareFunction(Box<BareFunctionDecl>),
/// A tuple type: `(i32, &str)`.
Tuple(Vec<Type>), Tuple(Vec<Type>),
/// A slice type (does *not* include the `&`): `[i32]`
Slice(Box<Type>), Slice(Box<Type>),
/// The `String` field is about the size or the constant representing the array's length. /// An array type.
///
/// The `String` field is a stringified version of the array's length parameter.
Array(Box<Type>, String), Array(Box<Type>, String),
/// A raw pointer type: `*const i32`, `*mut i32`
RawPointer(Mutability, Box<Type>), RawPointer(Mutability, Box<Type>),
BorrowedRef { /// A reference type: `&i32`, `&'a mut Foo`
lifetime: Option<Lifetime>, BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
mutability: Mutability,
type_: Box<Type>,
},
// `<Type as Trait>::Name` /// A qualified path to an associated item: `<Type as Trait>::Name`
QPath { QPath {
name: Symbol, name: Symbol,
self_type: Box<Type>, self_type: Box<Type>,
/// FIXME: This is a hack that should be removed; see [this discussion][1].
///
/// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093
self_def_id: Option<DefId>, self_def_id: Option<DefId>,
trait_: Box<Type>, trait_: Path,
}, },
// `_` /// A type that is inferred: `_`
Infer, Infer,
// `impl TraitA + TraitB + ...` /// An `impl Trait`: `impl TraitA + TraitB + ...`
ImplTrait(Vec<GenericBound>), ImplTrait(Vec<GenericBound>),
} }
@ -1514,34 +1513,8 @@ impl Type {
} }
crate fn generics(&self) -> Option<Vec<&Type>> { crate fn generics(&self) -> Option<Vec<&Type>> {
match *self { match self {
ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { ResolvedPath { path, .. } => path.generics(),
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
Some(
args.iter()
.filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect(),
)
} else {
None
}
}),
_ => None,
}
}
crate fn bindings(&self) -> Option<&[TypeBinding]> {
match *self {
ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
Some(&**bindings)
} else {
None
}
}),
_ => None, _ => None,
} }
} }
@ -1559,17 +1532,13 @@ impl Type {
QPath { self_type, trait_, name, .. } => (self_type, trait_, name), QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
_ => return None, _ => return None,
}; };
let trait_did = match **trait_ { Some((&self_, trait_.def_id(), *name))
ResolvedPath { did, .. } => did,
_ => return None,
};
Some((&self_, trait_did, *name))
} }
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> { fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self { let t: PrimitiveType = match *self {
ResolvedPath { did, .. } => return Some(did), ResolvedPath { did, .. } => return Some(did),
DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache), DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()), Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache), BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
@ -1601,8 +1570,12 @@ impl GetDefId for Type {
} }
} }
/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't /// A primitive (aka, builtin) type.
/// paths, like `Unit`. ///
/// This represents things like `i32`, `str`, etc.
///
/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
/// paths, like [`Self::Unit`].
#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
crate enum PrimitiveType { crate enum PrimitiveType {
Isize, Isize,
@ -2000,12 +1973,15 @@ impl Span {
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate struct Path { crate struct Path {
crate global: bool,
crate res: Res, crate res: Res,
crate segments: Vec<PathSegment>, crate segments: Vec<PathSegment>,
} }
impl Path { impl Path {
crate fn def_id(&self) -> DefId {
self.res.def_id()
}
crate fn last(&self) -> Symbol { crate fn last(&self) -> Symbol {
self.segments.last().expect("segments were empty").name self.segments.last().expect("segments were empty").name
} }
@ -2015,8 +1991,11 @@ impl Path {
} }
crate fn whole_name(&self) -> String { crate fn whole_name(&self) -> String {
String::from(if self.global { "::" } else { "" }) self.segments
+ &self.segments.iter().map(|s| s.name.to_string()).collect::<Vec<_>>().join("::") .iter()
.map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
.intersperse("::".into())
.collect()
} }
/// Checks if this is a `T::Name` path for an associated type. /// Checks if this is a `T::Name` path for an associated type.
@ -2028,6 +2007,33 @@ impl Path {
_ => false, _ => false,
} }
} }
crate fn generics(&self) -> Option<Vec<&Type>> {
self.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
Some(
args.iter()
.filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect(),
)
} else {
None
}
})
}
crate fn bindings(&self) -> Option<&[TypeBinding]> {
self.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
Some(&**bindings)
} else {
None
}
})
}
} }
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@ -2171,7 +2177,7 @@ crate struct Impl {
crate span: Span, crate span: Span,
crate unsafety: hir::Unsafety, crate unsafety: hir::Unsafety,
crate generics: Generics, crate generics: Generics,
crate trait_: Option<Type>, crate trait_: Option<Path>,
crate for_: Type, crate for_: Type,
crate items: Vec<Item>, crate items: Vec<Item>,
crate negative_polarity: bool, crate negative_polarity: bool,
@ -2182,7 +2188,8 @@ crate struct Impl {
impl Impl { impl Impl {
crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> { crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
self.trait_ self.trait_
.def_id() .as_ref()
.map(|t| t.def_id())
.map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
.unwrap_or_default() .unwrap_or_default()
} }

View file

@ -2,7 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder;
use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{ use crate::clean::{
inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type,
TypeBinding, Visibility, TypeBinding, Visibility,
}; };
use crate::core::DocContext; use crate::core::DocContext;
@ -147,7 +147,6 @@ pub(super) fn external_path(
let def_kind = cx.tcx.def_kind(did); let def_kind = cx.tcx.def_kind(did);
let name = cx.tcx.item_name(did); let name = cx.tcx.item_name(did);
Path { Path {
global: false,
res: Res::Def(def_kind, did), res: Res::Def(def_kind, did),
segments: vec![PathSegment { segments: vec![PathSegment {
name, name,
@ -156,39 +155,8 @@ pub(super) fn external_path(
} }
} }
crate fn strip_type(ty: Type) -> Type { /// Remove the generic arguments from a path.
match ty { crate fn strip_path_generics(path: Path) -> Path {
Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did },
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())
}
Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))),
Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s),
Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))),
Type::BorrowedRef { lifetime, mutability, type_ } => {
Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
}
Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath {
name,
self_def_id,
self_type: Box::new(strip_type(*self_type)),
trait_: Box::new(strip_type(*trait_)),
},
_ => ty,
}
}
crate fn strip_path(path: &Path) -> Path {
let segments = path let segments = path
.segments .segments
.iter() .iter()
@ -198,7 +166,7 @@ crate fn strip_path(path: &Path) -> Path {
}) })
.collect(); .collect();
Path { global: path.global, res: path.res, segments } Path { res: path.res, segments }
} }
crate fn qpath_to_string(p: &hir::QPath<'_>) -> String { crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {

View file

@ -203,7 +203,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
// masked crate then remove it completely. // masked crate then remove it completely.
if let clean::ImplItem(ref i) = *item.kind { if let clean::ImplItem(ref i) = *item.kind {
if self.cache.masked_crates.contains(&item.def_id.krate()) if self.cache.masked_crates.contains(&item.def_id.krate())
|| i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) || i.trait_
.as_ref()
.map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
|| i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
{ {
return None; return None;
@ -223,11 +225,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
// Collect all the implementors of traits. // Collect all the implementors of traits.
if let clean::ImplItem(ref i) = *item.kind { if let clean::ImplItem(ref i) = *item.kind {
if let Some(did) = i.trait_.def_id() { if let Some(trait_) = &i.trait_ {
if i.blanket_impl.is_none() { if i.blanket_impl.is_none() {
self.cache self.cache
.implementors .implementors
.entry(did) .entry(trait_.def_id())
.or_default() .or_default()
.push(Impl { impl_item: item.clone() }); .push(Impl { impl_item: item.clone() });
} }
@ -402,12 +404,8 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
} }
clean::DynTrait(ref bounds, _) clean::DynTrait(ref bounds, _)
| clean::BorrowedRef { type_: box 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(bounds[0].trait_.def_id());
self.cache.parent_stack.push(did); true
true
} else {
false
}
} }
ref t => { ref t => {
let prim_did = t let prim_did = t
@ -441,9 +439,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
} }
clean::DynTrait(ref bounds, _) clean::DynTrait(ref bounds, _)
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
if let Some(did) = bounds[0].trait_.def_id() { dids.insert(bounds[0].trait_.def_id());
dids.insert(did);
}
} }
ref t => { ref t => {
let did = t let did = t

View file

@ -7,14 +7,12 @@ use rustc_hir::def_id::DefId;
crate use renderer::{run_format, FormatRenderer}; crate use renderer::{run_format, FormatRenderer};
use crate::clean; use crate::clean;
use crate::clean::types::GetDefId;
use crate::formats::cache::Cache;
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
/// impl. /// impl.
crate enum AssocItemRender<'a> { crate enum AssocItemRender<'a> {
All, All,
DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }, DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
} }
/// For different handling of associated items from the Deref target of a type rather than the type /// For different handling of associated items from the Deref target of a type rather than the type
@ -40,10 +38,6 @@ impl Impl {
} }
crate fn trait_did(&self) -> Option<DefId> { crate fn trait_did(&self) -> Option<DefId> {
self.inner_impl().trait_.def_id() self.inner_impl().trait_.as_ref().map(|t| t.def_id())
}
crate fn trait_did_full(&self, cache: &Cache) -> Option<DefId> {
self.inner_impl().trait_.def_id_full(cache)
} }
} }

View file

@ -18,9 +18,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use crate::clean::{ use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType};
self, utils::find_nearest_parent_module, ExternalCrate, GetDefId, ItemId, PrimitiveType,
};
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::render::cache::ExternalLocation; use crate::html::render::cache::ExternalLocation;
@ -914,15 +912,10 @@ fn fmt_type<'cx>(
} }
} }
clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => { clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
let should_show_cast = match *trait_ { let should_show_cast = !trait_.segments.is_empty()
box clean::ResolvedPath { ref path, .. } => { && self_def_id
!path.segments.is_empty() .zip(Some(trait_.def_id()))
&& self_def_id .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_);
.zip(trait_.def_id())
.map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
}
_ => true,
};
if f.alternate() { if f.alternate() {
if should_show_cast { if should_show_cast {
write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
@ -936,36 +929,31 @@ fn fmt_type<'cx>(
write!(f, "{}::", self_type.print(cx))? write!(f, "{}::", self_type.print(cx))?
} }
}; };
match *trait_ { // It's pretty unsightly to look at `<A as B>::C` in output, and
// It's pretty unsightly to look at `<A as B>::C` in output, and // we've got hyperlinking on our side, so try to avoid longer
// we've got hyperlinking on our side, so try to avoid longer // notation as much as possible by making `C` a hyperlink to trait
// notation as much as possible by making `C` a hyperlink to trait // `B` to disambiguate.
// `B` to disambiguate. //
// // FIXME: this is still a lossy conversion and there should probably
// FIXME: this is still a lossy conversion and there should probably // be a better way of representing this in general? Most of
// be a better way of representing this in general? Most of // the ugliness comes from inlining across crates where
// the ugliness comes from inlining across crates where // everything comes in as a fully resolved QPath (hard to
// everything comes in as a fully resolved QPath (hard to // look at).
// look at). match href(trait_.def_id(), cx) {
box clean::ResolvedPath { did, .. } => { Ok((ref url, _, ref path)) if !f.alternate() => {
match href(did, cx) { write!(
Ok((ref url, _, ref path)) if !f.alternate() => { f,
write!( "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
f,
"<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
title=\"type {path}::{name}\">{name}</a>", title=\"type {path}::{name}\">{name}</a>",
url = url, url = url,
shortty = ItemType::AssocType, shortty = ItemType::AssocType,
name = name, name = name,
path = path.join("::") path = path.join("::")
)?; )?;
}
_ => write!(f, "{}", name)?,
}
Ok(())
} }
_ => write!(f, "{}", name), _ => write!(f, "{}", name)?,
} }
Ok(())
} }
} }
} }
@ -979,6 +967,15 @@ impl clean::Type {
} }
} }
impl clean::Path {
crate fn print<'b, 'a: 'b, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'b + Captures<'tcx> {
display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
}
}
impl clean::Impl { impl clean::Impl {
crate fn print<'a, 'tcx: 'a>( crate fn print<'a, 'tcx: 'a>(
&'a self, &'a self,

View file

@ -226,16 +226,13 @@ fn get_index_type(clean_type: &clean::Type) -> RenderType {
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> { fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
match *clean_type { match *clean_type {
clean::ResolvedPath { ref path, .. } => { clean::ResolvedPath { ref path, .. } => {
let segments = &path.segments; let path_segment = path.segments.last().unwrap();
let path_segment = segments.iter().last().unwrap_or_else(|| {
panic!(
"get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
clean_type, accept_generic
)
});
Some(path_segment.name) Some(path_segment.name)
} }
clean::DynTrait(ref bounds, _) => get_index_type_name(&bounds[0].trait_, accept_generic), clean::DynTrait(ref bounds, _) => {
let path = &bounds[0].trait_;
Some(path.segments.last().unwrap().name)
}
clean::Generic(s) if accept_generic => Some(s), clean::Generic(s) if accept_generic => Some(s),
clean::Primitive(ref p) => Some(p.as_sym()), clean::Primitive(ref p) => Some(p.as_sym()),
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
@ -324,7 +321,8 @@ crate fn get_real_types<'tcx>(
} }
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
for bound in bound.get_bounds().unwrap_or(&[]) { for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(ty) = bound.get_trait_type() { if let Some(path) = bound.get_trait_path() {
let ty = Type::ResolvedPath { did: path.def_id(), path };
let adds = get_real_types(generics, &ty, tcx, recurse + 1, res); let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
nb_added += adds; nb_added += adds;
if adds == 0 && !ty.is_full_generic() { if adds == 0 && !ty.is_full_generic() {

View file

@ -716,18 +716,12 @@ fn short_item_info(
// Render the list of items inside one of the sections "Trait Implementations", // Render the list of items inside one of the sections "Trait Implementations",
// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
fn render_impls( fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) {
cx: &Context<'_>,
w: &mut Buffer,
traits: &[&&Impl],
containing_item: &clean::Item,
) {
let cache = cx.cache();
let tcx = cx.tcx(); let tcx = cx.tcx();
let mut impls = traits let mut rendered_impls = impls
.iter() .iter()
.map(|i| { .map(|i| {
let did = i.trait_did_full(cache).unwrap(); let did = i.trait_did().unwrap();
let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
@ -751,8 +745,8 @@ fn render_impls(
buffer.into_inner() buffer.into_inner()
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
impls.sort(); rendered_impls.sort();
w.write_str(&impls.join("")); w.write_str(&rendered_impls.join(""));
} }
fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String { fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
@ -1097,13 +1091,11 @@ fn render_assoc_items(
return; return;
} }
if !traits.is_empty() { if !traits.is_empty() {
let deref_impl = traits.iter().find(|t| { let deref_impl =
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
});
if let Some(impl_) = deref_impl { if let Some(impl_) = deref_impl {
let has_deref_mut = traits.iter().any(|t| { let has_deref_mut =
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait() traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
});
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
} }
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
@ -1221,45 +1213,39 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html(); let mut out = Buffer::html();
let mut trait_ = String::new();
if let Some(did) = decl.output.def_id_full(cx.cache()) { if let Some(did) = decl.output.def_id_full(cx.cache()) {
if let Some(impls) = cx.cache().impls.get(&did) { if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls { for i in impls {
let impl_ = i.inner_impl(); let impl_ = i.inner_impl();
if impl_.trait_.def_id().map_or(false, |d| { if let Some(trait_) = &impl_.trait_ {
cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false) let trait_did = trait_.def_id();
}) {
if out.is_empty() { if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable) {
if out.is_empty() {
write!(
&mut out,
"<div class=\"notable\">Notable traits for {}</div>\
<code class=\"content\">",
impl_.for_.print(cx)
);
}
//use the "where" class here to make it small
write!( write!(
&mut out, &mut out,
"<div class=\"notable\">Notable traits for {}</div>\ "<span class=\"where fmt-newline\">{}</span>",
<code class=\"content\">", impl_.print(false, cx)
impl_.for_.print(cx)
); );
trait_.push_str(&impl_.for_.print(cx).to_string()); for it in &impl_.items {
} if let clean::TypedefItem(ref tydef, _) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
//use the "where" class here to make it small let empty_set = FxHashSet::default();
write!( let src_link =
&mut out, AssocItemLink::GotoSource(trait_did.into(), &empty_set);
"<span class=\"where fmt-newline\">{}</span>", assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx);
impl_.print(false, cx) out.push_str(";</span>");
); }
let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
for it in &impl_.items {
if let clean::TypedefItem(ref tydef, _) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
assoc_type(
&mut out,
it,
&[],
Some(&tydef.type_),
AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
"",
cx,
);
out.push_str(";</span>");
} }
} }
} }
@ -1302,7 +1288,7 @@ fn render_impl(
) { ) {
let cache = cx.cache(); let cache = cx.cache();
let traits = &cache.traits; let traits = &cache.traits;
let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); let trait_ = i.trait_did().map(|did| &traits[&did]);
let mut close_tags = String::new(); let mut close_tags = String::new();
// For trait implementations, the `interesting` output contains all methods that have doc // For trait implementations, the `interesting` output contains all methods that have doc
@ -1532,7 +1518,7 @@ fn render_impl(
if i.items.iter().any(|m| m.name == n) { if i.items.iter().any(|m| m.name == n) {
continue; continue;
} }
let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap(); let did = i.trait_.as_ref().unwrap().def_id();
let provided_methods = i.provided_trait_methods(cx.tcx()); let provided_methods = i.provided_trait_methods(cx.tcx());
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
@ -1917,9 +1903,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
} }
if v.iter().any(|i| i.inner_impl().trait_.is_some()) { if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| { if let Some(impl_) =
i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
}) { {
sidebar_deref_methods(cx, out, impl_, v); sidebar_deref_methods(cx, out, impl_, v);
} }
@ -2017,9 +2003,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
} }
} }
} }
let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| { let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait()
});
let inner_impl = target let inner_impl = target
.def_id_full(c) .def_id_full(c)
.or_else(|| { .or_else(|| {
@ -2086,10 +2070,10 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
fn get_id_for_impl_on_foreign_type( fn get_id_for_impl_on_foreign_type(
for_: &clean::Type, for_: &clean::Type,
trait_: &clean::Type, trait_: &clean::Path,
cx: &Context<'_>, cx: &Context<'_>,
) -> String { ) -> String {
small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),)) small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx)))
} }
fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
@ -2400,6 +2384,15 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
let mut visited = FxHashSet::default(); let mut visited = FxHashSet::default();
let mut work = VecDeque::new(); let mut work = VecDeque::new();
let mut process_path = |did: DefId| {
let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
if let Some(path) = fqp {
out.push(path.join("::"));
}
};
work.push_back(first_ty); work.push_back(first_ty);
while let Some(ty) = work.pop_front() { while let Some(ty) = work.pop_front() {
@ -2408,14 +2401,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
} }
match ty { match ty {
clean::Type::ResolvedPath { did, .. } => { clean::Type::ResolvedPath { did, .. } => process_path(did),
let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
if let Some(path) = fqp {
out.push(path.join("::"));
}
}
clean::Type::Tuple(tys) => { clean::Type::Tuple(tys) => {
work.extend(tys.into_iter()); work.extend(tys.into_iter());
} }
@ -2433,7 +2419,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
} }
clean::Type::QPath { self_type, trait_, .. } => { clean::Type::QPath { self_type, trait_, .. } => {
work.push_back(*self_type); work.push_back(*self_type);
work.push_back(*trait_); process_path(trait_.def_id());
} }
_ => {} _ => {}
} }

View file

@ -364,8 +364,11 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
use clean::GenericBound::*; use clean::GenericBound::*;
match bound { match bound {
TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ =
clean::ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound { GenericBound::TraitBound {
trait_: trait_.into_tcx(tcx), trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
modifier: from_trait_bound_modifier(modifier), modifier: from_trait_bound_modifier(modifier),
} }
@ -395,15 +398,12 @@ impl FromWithTcx<clean::Type> for Type {
param_names: Vec::new(), param_names: Vec::new(),
}, },
DynTrait(mut bounds, lt) => { DynTrait(mut bounds, lt) => {
let (path, id) = match bounds.remove(0).trait_ { let first_trait = bounds.remove(0).trait_;
ResolvedPath { path, did, .. } => (path, did),
_ => unreachable!(),
};
Type::ResolvedPath { Type::ResolvedPath {
name: path.whole_name(), name: first_trait.whole_name(),
id: from_item_id(id.into()), id: from_item_id(first_trait.def_id().into()),
args: path args: first_trait
.segments .segments
.last() .last()
.map(|args| Box::new(args.clone().args.into_tcx(tcx))), .map(|args| Box::new(args.clone().args.into_tcx(tcx))),
@ -434,11 +434,15 @@ impl FromWithTcx<clean::Type> for Type {
mutable: mutability == ast::Mutability::Mut, mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)), type_: Box::new((*type_).into_tcx(tcx)),
}, },
QPath { name, self_type, trait_, .. } => Type::QualifiedPath { QPath { name, self_type, trait_, .. } => {
name: name.to_string(), // FIXME: should `trait_` be a clean::Path equivalent in JSON?
self_type: Box::new((*self_type).into_tcx(tcx)), let trait_ = ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
trait_: Box::new((*trait_).into_tcx(tcx)), Type::QualifiedPath {
}, name: name.to_string(),
self_type: Box::new((*self_type).into_tcx(tcx)),
trait_: Box::new(trait_),
}
}
} }
} }
} }
@ -507,6 +511,11 @@ impl FromWithTcx<clean::Impl> for Impl {
blanket_impl, blanket_impl,
span: _span, span: _span,
} = impl_; } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| {
let did = path.def_id();
clean::ResolvedPath { path, did }.into_tcx(tcx)
});
Impl { Impl {
is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
generics: generics.into_tcx(tcx), generics: generics.into_tcx(tcx),
@ -514,7 +523,7 @@ impl FromWithTcx<clean::Impl> for Impl {
.into_iter() .into_iter()
.map(|x| x.to_string()) .map(|x| x.to_string())
.collect(), .collect(),
trait_: trait_.map(|x| x.into_tcx(tcx)), trait_,
for_: for_.into_tcx(tcx), for_: for_.into_tcx(tcx),
items: ids(items), items: ids(items),
negative: negative_polarity, negative: negative_polarity,

View file

@ -57,7 +57,9 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
// scan through included items ahead of time to splice in Deref targets to the "valid" sets // scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items { for it in &new_items {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { if cleaner.keep_impl(for_)
&& trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
{
let target = items let target = items
.iter() .iter()
.find_map(|item| match *item.kind { .find_map(|item| match *item.kind {
@ -78,7 +80,9 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
new_items.retain(|it| { new_items.retain(|it| {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
cleaner.keep_impl(for_) cleaner.keep_impl(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) || trait_
.as_ref()
.map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
|| blanket_impl.is_some() || blanket_impl.is_some()
} else { } else {
true true

View file

@ -134,7 +134,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
return None; return None;
} }
} }
if let Some(did) = imp.trait_.def_id() { if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
if did.is_local() && !self.retained.contains(&did.into()) { if did.is_local() && !self.retained.contains(&did.into()) {
debug!("ImplStripper: impl item for stripped trait; removing"); debug!("ImplStripper: impl item for stripped trait; removing");
return None; return None;