From: Noah Lev Date: Tue, 24 Aug 2021 17:15:19 +0000 (-0700) Subject: Use `Path` instead of `Type` in `PolyTrait` X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=91d3b7201e239c9966d43c0eaf1a4b636b0e06a8;p=rust.git Use `Path` instead of `Type` in `PolyTrait` The change to `impl Clean for hir::TraitRef<'_>` was necessary to fix a test failure for `src/test/rustdoc/trait-alias-mention.rs`. Here's why: The old code path was through `impl Clean for hir::TraitRef<'_>`, which called `resolve_type`, which in turn called `register_res`. Now, because `PolyTrait` uses a `Path` instead of a `Type`, the impl of `Clean` was being run, which did not call `register_res`, causing the trait alias to not be recorded in the `external_paths` cache. --- diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c83a191baf5..fe3edd4112b 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -118,7 +118,7 @@ fn generate_for_trait( span: Span::dummy(), unsafety: hir::Unsafety::Normal, generics: new_generics, - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap().expect_path()), + trait_: Some(trait_ref.clean(self.cx).get_trait_path().unwrap()), for_: ty.clean(self.cx), items: Vec::new(), negative_polarity, @@ -353,48 +353,35 @@ fn make_final_bounds( if let Some(data) = ty_to_fn.get(&ty) { let (poly_trait, output) = (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); - let new_ty = match poly_trait.trait_ { - Type::ResolvedPath { ref path, ref did } => { - 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 { - GenericArgs::AngleBracketed { args, .. } => { - let types = args - .iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty.clone()), - _ => None, - }) - .collect(); - (types, None) - } - GenericArgs::Parenthesized { inputs, output, .. } => { - (inputs, output) - } - }; + let mut new_path = poly_trait.trait_.clone(); + let last_segment = new_path.segments.pop().expect("segments were empty"); + + let (old_input, old_output) = match last_segment.args { + GenericArgs::AngleBracketed { args, .. } => { + let types = args + .iter() + .filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }) + .collect(); + (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 - ); - } + 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 }; + let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; - new_path - .segments - .push(PathSegment { name: last_segment.name, args: new_params }); + new_path + .segments + .push(PathSegment { name: last_segment.name, args: new_params }); - Type::ResolvedPath { path: new_path, did: *did } - } - _ => panic!("Unexpected data: {:?}, {:?}", ty, data), - }; 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, )); } @@ -476,7 +463,7 @@ fn param_env_to_generics( let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); - let mut ty_to_traits: FxHashMap> = Default::default(); + let mut ty_to_traits: FxHashMap> = Default::default(); let mut ty_to_fn: FxHashMap, Option)> = Default::default(); @@ -511,11 +498,11 @@ fn param_env_to_generics( if b.is_sized_bound(self.cx) { has_sized.insert(ty.clone()); } else if !b - .get_trait_type() - .and_then(|t| { + .get_trait_path() + .and_then(|trait_| { ty_to_traits .get(&ty) - .map(|bounds| bounds.contains(&strip_type(t.clone()))) + .map(|bounds| bounds.contains(&strip_path(trait_.clone()))) }) .unwrap_or(false) { @@ -532,7 +519,7 @@ fn param_env_to_generics( // that we don't end up with duplicate bounds (e.g., for<'b, 'b>) for_generics.extend(p.generic_params.clone()); p.generic_params = for_generics.into_iter().collect(); - self.is_fn_ty(&p.trait_) + self.is_fn_trait(&p.trait_) } _ => false, }; @@ -558,78 +545,59 @@ fn param_env_to_generics( match lhs { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; - match **trait_ { - 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 { - ty_to_fn - .entry(*ty.clone()) - .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) - .or_insert((None, Some(rhs))); - continue; - } - - let args = &mut new_trait_path - .segments - .last_mut() - .expect("segments were empty") - .args; - - match args { - // Convert something like ' = u8' - // to 'T: Iterator' - 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` - // 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()); + let mut new_trait = *trait_.clone(); + + if self.is_fn_trait(trait_) && left_name == sym::Output { + ty_to_fn + .entry(*ty.clone()) + .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) + .or_insert((None, Some(rhs))); + continue; + } + + let args = &mut new_trait + .segments + .last_mut() + .expect("segments were empty") + .args; + + match args { + // Convert something like ' = u8' + // to 'T: Iterator' + 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 } - _ => panic!("Unexpected trait {:?} for {:?}", trait_, item_def_id), } + + 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` + // 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), } @@ -721,16 +689,12 @@ fn unstable_debug_sort(&self, vec: &mut Vec) { 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; - match ty { - &Type::ResolvedPath { did, .. } => { - did == tcx.require_lang_item(LangItem::Fn, None) - || did == tcx.require_lang_item(LangItem::FnMut, None) - || did == tcx.require_lang_item(LangItem::FnOnce, None) - } - _ => false, - } + let did = path.res.def_id(); + did == tcx.require_lang_item(LangItem::Fn, None) + || did == tcx.require_lang_item(LangItem::FnMut, None) + || did == tcx.require_lang_item(LangItem::FnOnce, None) } } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 4385c1adc09..410b6a42d76 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -114,9 +114,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .clean(self.cx), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some( - trait_ref.clean(self.cx).get_trait_type().unwrap().expect_path(), - ), + trait_: Some(trait_ref.clean(self.cx).get_trait_path().unwrap()), for_: ty.clean(self.cx), items: self .cx diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 7a08e54d4b1..bee10e72fa0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -455,11 +455,20 @@ fn merge_attrs( } // Return if the trait itself or any types of the generic parameters are doc(hidden). - let mut stack: Vec<&Type> = trait_.iter().collect(); - stack.push(&for_); + let mut stack: Vec<&Type> = vec![&for_]; + + if let Some(did) = trait_.as_ref().map(|t| t.res.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() { 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; } } @@ -468,8 +477,8 @@ fn merge_attrs( } } - if let Some(trait_did) = trait_.def_id() { - record_extern_trait(cx, trait_did); + if let Some(did) = trait_.as_ref().map(|t| t.res.def_id()) { + record_extern_trait(cx, did); } let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); @@ -483,7 +492,7 @@ fn merge_attrs( span: clean::types::rustc_span(did, cx.tcx), unsafety: hir::Unsafety::Normal, generics, - trait_: trait_.map(|t| t.expect_path()), + trait_, for_, items: trait_items, negative_polarity: polarity.clean(cx), @@ -620,11 +629,10 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: ref mut bounds, .. } if *s == kw::SelfUpper => { - bounds.retain(|bound| match *bound { - clean::GenericBound::TraitBound( - clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. }, - _, - ) => did != trait_did, + bounds.retain(|bound| match bound { + clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { + trait_.res.def_id() != trait_did + } _ => true, }); } @@ -632,18 +640,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 { - ty: - clean::QPath { - self_type: box clean::Generic(ref s), - trait_: box clean::ResolvedPath { did, .. }, - name: ref _name, - .. - }, - ref bounds, + ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. }, + bounds, .. - } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), + } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.res.def_id() == trait_did), _ => true, }); g diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 21389fa38a8..285314a5cb6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -152,8 +152,8 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound { } } -impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { - fn clean(&self, cx: &mut DocContext<'_>) -> Type { +impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { let (trait_ref, bounds) = *self; let kind = cx.tcx.def_kind(trait_ref.def_id).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { @@ -168,7 +168,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type { debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); - ResolvedPath { path, did: trait_ref.def_id } + path } } @@ -905,7 +905,9 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type { impl Clean for hir::TraitRef<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Path { - self.path.clean(cx) + let path = self.path.clean(cx); + register_res(cx, path.res); + path } } @@ -1111,9 +1113,8 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item { if *name != my_name { return None; } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, + if trait_.res.def_id() != self.container.id() { + return None; } match **self_type { Generic(ref s) if *s == kw::SelfUpper => {} @@ -1286,11 +1287,12 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { res: Res::Def(DefKind::Trait, trait_def), segments: trait_segments.clean(cx), }; + register_res(cx, trait_path.res); Type::QPath { name: p.segments.last().expect("segments were empty").ident.name, self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_type: box qself.clean(cx), - trait_: box resolve_type(cx, trait_path), + trait_: box trait_path, } } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -1302,11 +1304,12 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { _ => bug!("clean: expected associated type, found `{:?}`", ty), }; let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); + register_res(cx, trait_path.res); Type::QPath { name: segment.ident.name, self_def_id: res.opt_def_id(), self_type: box qself.clean(cx), - trait_: box resolve_type(cx, trait_path), + trait_: box trait_path, } } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), @@ -1475,10 +1478,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type { let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - let bound = PolyTrait { - trait_: ResolvedPath { path, did }, - generic_params: Vec::new(), - }; + let bound = PolyTrait { trait_: path, generic_params: Vec::new() }; bounds.push(bound); } @@ -1491,10 +1491,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type { } let path = external_path(cx, did, false, bindings, substs); - bounds.insert( - 0, - PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, - ); + bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() }); DynTrait(bounds, lifetime) } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 257af6ab910..101fdd465b7 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -99,17 +99,13 @@ clean::GenericBound::TraitBound(ref mut tr, _) => tr, 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 // of, the bound's trait `did` then we can keep going, otherwise // 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_.res.def_id(), trait_did) { 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 { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a5f71c4a849..da06737394d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1114,7 +1114,7 @@ impl GenericBound { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( - PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, + PolyTrait { trait_: path, generic_params: Vec::new() }, hir::TraitBoundModifier::Maybe, ) } @@ -1136,7 +1136,7 @@ impl GenericBound { None } - crate fn get_trait_type(&self) -> Option { + crate fn get_trait_path(&self) -> Option { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { Some(trait_.clone()) } else { @@ -1368,7 +1368,7 @@ fn def_id_full(&self, cache: &Cache) -> Option { /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct PolyTrait { - crate trait_: Type, + crate trait_: Path, crate generic_params: Vec, } @@ -1408,7 +1408,8 @@ fn def_id_full(&self, cache: &Cache) -> Option { name: Symbol, self_type: Box, self_def_id: Option, - trait_: Box, + // FIXME: remove this `Box`; it's unnecessary + trait_: Box, }, // `_` @@ -1473,15 +1474,6 @@ impl Type { } } - // FIXME: temporary - #[track_caller] - crate fn expect_path(self) -> Path { - match self { - ResolvedPath { path, .. } => path, - _ => panic!("not a ResolvedPath: {:?}", self), - } - } - crate fn is_self_type(&self) -> bool { match *self { Generic(name) => name == kw::SelfUpper, @@ -1496,19 +1488,6 @@ impl Type { } } - 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, - } - } - crate fn is_full_generic(&self) -> bool { matches!(self, Type::Generic(_)) } @@ -1522,17 +1501,13 @@ impl Type { QPath { self_type, trait_, name, .. } => (self_type, trait_, name), _ => return None, }; - let trait_did = match **trait_ { - ResolvedPath { did, .. } => did, - _ => return None, - }; - Some((&self_, trait_did, *name)) + Some((&self_, trait_.res.def_id(), *name)) } fn inner_def_id(&self, cache: Option<&Cache>) -> Option { let t: PrimitiveType = match *self { ResolvedPath { did, .. } => return Some(did), - DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache), + DynTrait(ref bounds, _) => return Some(bounds[0].trait_.res.def_id()), 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), @@ -2006,6 +1981,16 @@ impl Path { } }) } + + crate fn bindings(&self) -> Option<&[TypeBinding]> { + self.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { + Some(&**bindings) + } else { + None + } + }) + } } // FIXME: this is temporary diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 55dfa2711db..487efdc060f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,7 +2,7 @@ use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ 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, }; use crate::core::DocContext; @@ -156,39 +156,7 @@ pub(super) fn external_path( } } -crate fn strip_type(ty: Type) -> Type { - match ty { - 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 { +crate fn strip_path(path: Path) -> Path { let segments = path .segments .iter() diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4338ed7160c..7093bcf6adf 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,9 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; -use crate::clean::{ - self, utils::find_nearest_parent_module, ExternalCrate, GetDefId, ItemId, PrimitiveType, -}; +use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; 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 } => { - let should_show_cast = match *trait_ { - box clean::ResolvedPath { ref path, .. } => { - !path.segments.is_empty() - && self_def_id - .zip(trait_.def_id()) - .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_) - } - _ => true, - }; + let should_show_cast = !trait_.segments.is_empty() + && self_def_id + .zip(Some(trait_.res.def_id())) + .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_); if f.alternate() { if should_show_cast { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? @@ -936,36 +929,31 @@ fn fmt_type<'cx>( write!(f, "{}::", self_type.print(cx))? } }; - match *trait_ { - // It's pretty unsightly to look at `::C` in output, and - // we've got hyperlinking on our side, so try to avoid longer - // notation as much as possible by making `C` a hyperlink to trait - // `B` to disambiguate. - // - // FIXME: this is still a lossy conversion and there should probably - // be a better way of representing this in general? Most of - // the ugliness comes from inlining across crates where - // everything comes in as a fully resolved QPath (hard to - // look at). - box clean::ResolvedPath { did, .. } => { - match href(did, cx) { - Ok((ref url, _, ref path)) if !f.alternate() => { - write!( - f, - "::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + match href(trait_.res.def_id(), cx) { + Ok((ref url, _, ref path)) if !f.alternate() => { + write!( + f, + "{name}", - url = url, - shortty = ItemType::AssocType, - name = name, - path = path.join("::") - )?; - } - _ => write!(f, "{}", name)?, - } - Ok(()) + url = url, + shortty = ItemType::AssocType, + name = name, + path = path.join("::") + )?; } - _ => write!(f, "{}", name), + _ => write!(f, "{}", name)?, } + Ok(()) } } } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index edd1d8b98fc..7336b8b41ac 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -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 { match *clean_type { clean::ResolvedPath { ref path, .. } => { - let segments = &path.segments; - 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 - ) - }); + let path_segment = path.segments.last().unwrap(); 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::Primitive(ref p) => Some(p.as_sym()), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), @@ -324,7 +321,8 @@ fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> u } if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { 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.res.def_id(), path }; let adds = get_real_types(generics, &ty, tcx, recurse + 1, res); nb_added += adds; if adds == 0 && !ty.is_full_generic() { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 83cd2af169a..74236999003 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2370,6 +2370,15 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { let mut visited = FxHashSet::default(); 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); while let Some(ty) = work.pop_front() { @@ -2378,14 +2387,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { } match ty { - clean::Type::ResolvedPath { 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::ResolvedPath { did, .. } => process_path(did), clean::Type::Tuple(tys) => { work.extend(tys.into_iter()); } @@ -2403,7 +2405,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { } clean::Type::QPath { self_type, trait_, .. } => { work.push_back(*self_type); - work.push_back(*trait_); + process_path(trait_.res.def_id()); } _ => {} } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index df9a07499ac..10320baaf93 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -363,8 +363,11 @@ fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self { use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = + clean::ResolvedPath { did: trait_.res.def_id(), path: trait_ }.into_tcx(tcx); GenericBound::TraitBound { - trait_: trait_.into_tcx(tcx), + trait_, generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), modifier: from_trait_bound_modifier(modifier), } @@ -394,15 +397,12 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { param_names: Vec::new(), }, DynTrait(mut bounds, lt) => { - let (path, id) = match bounds.remove(0).trait_ { - ResolvedPath { path, did, .. } => (path, did), - _ => unreachable!(), - }; + let first_trait = bounds.remove(0).trait_; Type::ResolvedPath { - name: path.whole_name(), - id: from_item_id(id.into()), - args: path + name: first_trait.whole_name(), + id: from_item_id(first_trait.res.def_id().into()), + args: first_trait .segments .last() .map(|args| Box::new(args.clone().args.into_tcx(tcx))), @@ -434,11 +434,15 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, - QPath { name, self_type, trait_, .. } => Type::QualifiedPath { - name: name.to_string(), - self_type: Box::new((*self_type).into_tcx(tcx)), - trait_: Box::new((*trait_).into_tcx(tcx)), - }, + QPath { name, self_type, trait_, .. } => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = ResolvedPath { did: trait_.res.def_id(), path: *trait_ }.into_tcx(tcx); + Type::QualifiedPath { + name: name.to_string(), + self_type: Box::new((*self_type).into_tcx(tcx)), + trait_: Box::new(trait_), + } + } } } } @@ -507,7 +511,7 @@ fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { blanket_impl, span: _span, } = impl_; - // FIXME: should `trait_` be a Path in JSON? + // FIXME: should `trait_` be a clean::Path equivalent in JSON? let trait_ = trait_.map(|path| { let did = path.res.def_id(); clean::ResolvedPath { path, did }.into_tcx(tcx)