summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/clean
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r--src/librustdoc/clean/blanket_impl.rs5
-rw-r--r--src/librustdoc/clean/cfg.rs1
-rw-r--r--src/librustdoc/clean/inline.rs106
-rw-r--r--src/librustdoc/clean/mod.rs288
-rw-r--r--src/librustdoc/clean/simplify.rs6
-rw-r--r--src/librustdoc/clean/types.rs218
-rw-r--r--src/librustdoc/clean/types/tests.rs13
-rw-r--r--src/librustdoc/clean/utils.rs6
8 files changed, 298 insertions, 345 deletions
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index bcdbbcacc..3a3bf6a7a 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,6 +1,6 @@
use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_hir as hir;
-use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::traits;
use rustc_middle::ty::ToPredicate;
use rustc_span::DUMMY_SP;
@@ -47,8 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
// Require the type the impl is implemented on to match
// our type, and ignore the impl if there was a mismatch.
- let cause = traits::ObligationCause::dummy();
- let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
+ let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else {
continue
};
let InferOk { value: (), obligations } = eq_result;
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index dd58a5b51..5177cffe6 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -517,6 +517,7 @@ impl<'a> fmt::Display for Display<'a> {
"aarch64" => "AArch64",
"arm" => "ARM",
"asmjs" => "JavaScript",
+ "loongarch64" => "LoongArch LA64",
"m68k" => "M68k",
"mips" => "MIPS",
"mips64" => "MIPS-64",
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 148243683..cc5d13808 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -36,15 +36,11 @@ use crate::formats::item_type::ItemType;
///
/// The returned value is `None` if the definition could not be inlined,
/// and `Some` of a vector of items if it was successfully expanded.
-///
-/// `parent_module` refers to the parent of the *re-export*, not the original item.
pub(crate) fn try_inline(
cx: &mut DocContext<'_>,
- parent_module: DefId,
- import_def_id: Option<DefId>,
res: Res,
name: Symbol,
- attrs: Option<&[ast::Attribute]>,
+ attrs: Option<(&[ast::Attribute], Option<DefId>)>,
visited: &mut DefIdSet,
) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?;
@@ -55,38 +51,17 @@ pub(crate) fn try_inline(
debug!("attrs={:?}", attrs);
- let attrs_without_docs = attrs.map(|attrs| {
- attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>()
+ let attrs_without_docs = attrs.map(|(attrs, def_id)| {
+ (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id)
});
- // We need this ugly code because:
- //
- // ```
- // attrs_without_docs.map(|a| a.as_slice())
- // ```
- //
- // will fail because it returns a temporary slice and:
- //
- // ```
- // attrs_without_docs.map(|s| {
- // vec = s.as_slice();
- // vec
- // })
- // ```
- //
- // will fail because we're moving an uninitialized variable into a closure.
- let vec;
- let attrs_without_docs = match attrs_without_docs {
- Some(s) => {
- vec = s;
- Some(vec.as_slice())
- }
- None => None,
- };
+ let attrs_without_docs =
+ attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id));
+ let import_def_id = attrs.and_then(|(_, def_id)| def_id);
let kind = match res {
Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, ItemType::Trait);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::TraitItem(Box::new(build_external_trait(cx, did)))
}
Res::Def(DefKind::Fn, did) => {
@@ -95,27 +70,27 @@ pub(crate) fn try_inline(
}
Res::Def(DefKind::Struct, did) => {
record_extern_fqn(cx, did, ItemType::Struct);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::StructItem(build_struct(cx, did))
}
Res::Def(DefKind::Union, did) => {
record_extern_fqn(cx, did, ItemType::Union);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::UnionItem(build_union(cx, did))
}
Res::Def(DefKind::TyAlias, did) => {
record_extern_fqn(cx, did, ItemType::Typedef);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::TypedefItem(build_type_alias(cx, did))
}
Res::Def(DefKind::Enum, did) => {
record_extern_fqn(cx, did, ItemType::Enum);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::EnumItem(build_enum(cx, did))
}
Res::Def(DefKind::ForeignTy, did) => {
record_extern_fqn(cx, did, ItemType::ForeignType);
- build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
+ build_impls(cx, did, attrs_without_docs, &mut ret);
clean::ForeignTypeItem
}
// Never inline enum variants but leave them shown as re-exports.
@@ -136,7 +111,7 @@ pub(crate) fn try_inline(
clean::ConstantItem(build_const(cx, did))
}
Res::Def(DefKind::Macro(kind), did) => {
- let mac = build_macro(cx, did, name, import_def_id);
+ let mac = build_macro(cx, did, name, import_def_id, kind);
let type_kind = match kind {
MacroKind::Bang => ItemType::Macro,
@@ -149,7 +124,7 @@ pub(crate) fn try_inline(
_ => return None,
};
- let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs);
+ let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
cx.inlined.insert(did.into());
let mut item =
clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg);
@@ -177,8 +152,7 @@ pub(crate) fn try_inline_glob(
// reexported by the glob, e.g. because they are shadowed by something else.
let reexports = cx
.tcx
- .module_reexports(current_mod)
- .unwrap_or_default()
+ .module_children_reexports(current_mod)
.iter()
.filter_map(|child| child.res.opt_def_id())
.collect();
@@ -316,9 +290,8 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef>
/// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
pub(crate) fn build_impls(
cx: &mut DocContext<'_>,
- parent_module: Option<DefId>,
did: DefId,
- attrs: Option<&[ast::Attribute]>,
+ attrs: Option<(&[ast::Attribute], Option<DefId>)>,
ret: &mut Vec<clean::Item>,
) {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
@@ -326,7 +299,7 @@ pub(crate) fn build_impls(
// for each implementation of an item represented by `did`, build the clean::Item for that impl
for &did in tcx.inherent_impls(did).iter() {
- build_impl(cx, parent_module, did, attrs, ret);
+ build_impl(cx, did, attrs, ret);
}
// This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate.
@@ -340,28 +313,26 @@ pub(crate) fn build_impls(
let type_ =
if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
for &did in tcx.incoherent_impls(type_) {
- build_impl(cx, parent_module, did, attrs, ret);
+ build_impl(cx, did, attrs, ret);
}
}
}
-/// `parent_module` refers to the parent of the re-export, not the original item
pub(crate) fn merge_attrs(
cx: &mut DocContext<'_>,
- parent_module: Option<DefId>,
old_attrs: &[ast::Attribute],
- new_attrs: Option<&[ast::Attribute]>,
+ new_attrs: Option<(&[ast::Attribute], Option<DefId>)>,
) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
// NOTE: If we have additional attributes (from a re-export),
// always insert them first. This ensure that re-export
// doc comments show up before the original doc comments
// when we render them.
- if let Some(inner) = new_attrs {
+ if let Some((inner, item_id)) = new_attrs {
let mut both = inner.to_vec();
both.extend_from_slice(old_attrs);
(
- if let Some(new_id) = parent_module {
- Attributes::from_ast_with_additional(old_attrs, (inner, new_id))
+ if let Some(item_id) = item_id {
+ Attributes::from_ast_with_additional(old_attrs, (inner, item_id))
} else {
Attributes::from_ast(&both)
},
@@ -375,9 +346,8 @@ pub(crate) fn merge_attrs(
/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
pub(crate) fn build_impl(
cx: &mut DocContext<'_>,
- parent_module: Option<DefId>,
did: DefId,
- attrs: Option<&[ast::Attribute]>,
+ attrs: Option<(&[ast::Attribute], Option<DefId>)>,
ret: &mut Vec<clean::Item>,
) {
if !cx.inlined.insert(did.into()) {
@@ -539,7 +509,7 @@ pub(crate) fn build_impl(
record_extern_trait(cx, did);
}
- let (merged_attrs, cfg) = merge_attrs(cx, parent_module, load_attrs(cx, did), attrs);
+ let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
trace!("merged_attrs={:?}", merged_attrs);
trace!(
@@ -587,7 +557,7 @@ fn build_module_items(
// If we're re-exporting a re-export it may actually re-export something in
// two namespaces, so the target may be listed twice. Make sure we only
// visit each node at most once.
- for &item in cx.tcx.module_children(did).iter() {
+ for item in cx.tcx.module_children(did).iter() {
if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.opt_def_id()
@@ -635,7 +605,7 @@ fn build_module_items(
cfg: None,
inline_stmt_id: None,
});
- } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
+ } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) {
items.extend(i)
}
}
@@ -681,18 +651,24 @@ fn build_macro(
def_id: DefId,
name: Symbol,
import_def_id: Option<DefId>,
+ macro_kind: MacroKind,
) -> clean::ItemKind {
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
- LoadedMacro::MacroDef(item_def, _) => {
- if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
- let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id));
- clean::MacroItem(clean::Macro {
- source: utils::display_macro_source(cx, name, def, def_id, vis),
- })
- } else {
- unreachable!()
+ LoadedMacro::MacroDef(item_def, _) => match macro_kind {
+ MacroKind::Bang => {
+ if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
+ let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id));
+ clean::MacroItem(clean::Macro {
+ source: utils::display_macro_source(cx, name, def, def_id, vis),
+ })
+ } else {
+ unreachable!()
+ }
}
- }
+ MacroKind::Derive | MacroKind::Attr => {
+ clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
+ }
+ },
LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
kind: ext.macro_kind(),
helpers: ext.helper_attrs,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3edc2cd2e..5fa0c120f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -21,25 +21,24 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
use rustc_hir::PredicateOrigin;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
+use rustc_middle::metadata::Reexport;
use rustc_middle::middle::resolve_bound_vars as rbv;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, ExpnKind};
-use std::assert_matches::assert_matches;
+use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
-use std::default::Default;
use std::hash::Hash;
use std::mem;
use thin_vec::ThinVec;
-use crate::clean::inline::merge_attrs;
use crate::core::{self, DocContext, ImplTraitParam};
use crate::formats::item_type::ItemType;
use crate::visit_ast::Module as DocModule;
@@ -270,15 +269,7 @@ fn clean_where_predicate<'tcx>(
let bound_params = wbp
.bound_generic_params
.iter()
- .map(|param| {
- // Higher-ranked params must be lifetimes.
- // Higher-ranked lifetimes can't have bounds.
- assert_matches!(
- param,
- hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
- );
- Lifetime(param.name.ident().name)
- })
+ .map(|param| clean_generic_param(cx, None, param))
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
@@ -324,7 +315,7 @@ pub(crate) fn clean_predicate<'tcx>(
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
@@ -410,7 +401,7 @@ fn clean_projection_predicate<'tcx>(
.collect_referenced_late_bound_regions(&pred)
.into_iter()
.filter_map(|br| match br {
- ty::BrNamed(_, name) if br.is_named() => Some(Lifetime(name)),
+ ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
_ => None,
})
.collect();
@@ -427,7 +418,7 @@ fn clean_projection<'tcx>(
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
- if cx.tcx.def_kind(ty.skip_binder().def_id) == DefKind::ImplTraitPlaceholder {
+ if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
let bounds = cx
.tcx
.explicit_item_bounds(ty.skip_binder().def_id)
@@ -508,7 +499,6 @@ fn clean_generic_param_def<'tcx>(
ty::GenericParamDefKind::Const { has_default } => (
def.name,
GenericParamDefKind::Const {
- did: def.def_id,
ty: Box::new(clean_middle_ty(
ty::Binder::dummy(
cx.tcx
@@ -578,7 +568,6 @@ fn clean_generic_param<'tcx>(
hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name,
GenericParamDefKind::Const {
- did: param.def_id.to_def_id(),
ty: Box::new(clean_ty(ty, cx)),
default: default
.map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
@@ -831,7 +820,7 @@ fn clean_ty_generics<'tcx>(
p.get_bound_params()
.into_iter()
.flatten()
- .map(|param| GenericParamDef::lifetime(param.0))
+ .cloned()
.collect(),
));
}
@@ -919,6 +908,38 @@ fn clean_ty_generics<'tcx>(
}
}
+fn clean_proc_macro<'tcx>(
+ item: &hir::Item<'tcx>,
+ name: &mut Symbol,
+ kind: MacroKind,
+ cx: &mut DocContext<'tcx>,
+) -> ItemKind {
+ let attrs = cx.tcx.hir().attrs(item.hir_id());
+ if kind == MacroKind::Derive &&
+ let Some(derive_name) = attrs
+ .lists(sym::proc_macro_derive)
+ .find_map(|mi| mi.ident())
+ {
+ *name = derive_name.name;
+ }
+
+ let mut helpers = Vec::new();
+ for mi in attrs.lists(sym::proc_macro_derive) {
+ if !mi.has_name(sym::attributes) {
+ continue;
+ }
+
+ if let Some(list) = mi.meta_item_list() {
+ for inner_mi in list {
+ if let Some(ident) = inner_mi.ident() {
+ helpers.push(ident.name);
+ }
+ }
+ }
+ }
+ ProcMacroItem(ProcMacro { kind, helpers })
+}
+
fn clean_fn_or_proc_macro<'tcx>(
item: &hir::Item<'tcx>,
sig: &hir::FnSig<'tcx>,
@@ -940,31 +961,7 @@ fn clean_fn_or_proc_macro<'tcx>(
}
});
match macro_kind {
- Some(kind) => {
- if kind == MacroKind::Derive {
- *name = attrs
- .lists(sym::proc_macro_derive)
- .find_map(|mi| mi.ident())
- .expect("proc-macro derives require a name")
- .name;
- }
-
- let mut helpers = Vec::new();
- for mi in attrs.lists(sym::proc_macro_derive) {
- if !mi.has_name(sym::attributes) {
- continue;
- }
-
- if let Some(list) = mi.meta_item_list() {
- for inner_mi in list {
- if let Some(ident) = inner_mi.ident() {
- helpers.push(ident.name);
- }
- }
- }
- }
- ProcMacroItem(ProcMacro { kind, helpers })
- }
+ Some(kind) => clean_proc_macro(item, name, kind, cx),
None => {
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
clean_fn_decl_legacy_const_generics(&mut func, attrs);
@@ -2013,7 +2010,8 @@ fn clean_generic_args<'tcx>(
generic_args: &hir::GenericArgs<'tcx>,
cx: &mut DocContext<'tcx>,
) -> GenericArgs {
- if generic_args.parenthesized {
+ // FIXME(return_type_notation): Fix RTN parens rendering
+ if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
let output = clean_ty(generic_args.bindings[0].ty(), cx);
let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
let inputs =
@@ -2066,110 +2064,44 @@ fn clean_bare_fn_ty<'tcx>(
BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
}
-/// This visitor is used to go through only the "top level" of a item and not enter any sub
-/// item while looking for a given `Ident` which is stored into `item` if found.
-struct OneLevelVisitor<'hir> {
- map: rustc_middle::hir::map::Map<'hir>,
- item: Option<&'hir hir::Item<'hir>>,
- looking_for: Ident,
+pub(crate) fn reexport_chain<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ import_def_id: LocalDefId,
target_def_id: LocalDefId,
-}
-
-impl<'hir> OneLevelVisitor<'hir> {
- fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self {
- Self { map, item: None, looking_for: Ident::empty(), target_def_id }
- }
-
- fn reset(&mut self, looking_for: Ident) {
- self.looking_for = looking_for;
- self.item = None;
- }
-}
-
-impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
- type NestedFilter = rustc_middle::hir::nested_filter::All;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.map
- }
-
- fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
- if self.item.is_none()
- && item.ident == self.looking_for
- && (matches!(item.kind, hir::ItemKind::Use(_, _))
- || item.owner_id.def_id == self.target_def_id)
+) -> &'tcx [Reexport] {
+ for child in tcx.module_children_reexports(tcx.local_parent(import_def_id)) {
+ if child.res.opt_def_id() == Some(target_def_id.to_def_id())
+ && child.reexport_chain[0].id() == Some(import_def_id.to_def_id())
{
- self.item = Some(item);
+ return &child.reexport_chain;
}
}
+ &[]
}
-/// Because a `Use` item directly links to the imported item, we need to manually go through each
-/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
-/// if we found the "end item" (the imported one), we stop there because we don't need its
-/// documentation. Otherwise, we repeat the same operation until we find the "end item".
+/// Collect attributes from the whole import chain.
fn get_all_import_attributes<'hir>(
- mut item: &hir::Item<'hir>,
- tcx: TyCtxt<'hir>,
+ cx: &mut DocContext<'hir>,
+ import_def_id: LocalDefId,
target_def_id: LocalDefId,
- attributes: &mut Vec<ast::Attribute>,
is_inline: bool,
-) {
+) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> {
+ let mut attrs = Vec::new();
let mut first = true;
- let hir_map = tcx.hir();
- let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
- let mut visited = FxHashSet::default();
-
- // If the item is an import and has at least a path with two parts, we go into it.
- while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) {
+ for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id)
+ .iter()
+ .flat_map(|reexport| reexport.id())
+ {
+ let import_attrs = inline::load_attrs(cx, def_id);
if first {
// This is the "original" reexport so we get all its attributes without filtering them.
- attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
+ attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect();
first = false;
} else {
- add_without_unwanted_attributes(attributes, hir_map.attrs(item.hir_id()), is_inline);
- }
-
- let def_id = if let [.., parent_segment, _] = &path.segments {
- match parent_segment.res {
- hir::def::Res::Def(_, def_id) => def_id,
- _ if parent_segment.ident.name == kw::Crate => {
- // In case the "parent" is the crate, it'll give `Res::Err` so we need to
- // circumvent it this way.
- tcx.parent(item.owner_id.def_id.to_def_id())
- }
- _ => break,
- }
- } else {
- // If the path doesn't have a parent, then the parent is the current module.
- tcx.parent(item.owner_id.def_id.to_def_id())
- };
-
- let Some(parent) = hir_map.get_if_local(def_id) else { break };
-
- // We get the `Ident` we will be looking for into `item`.
- let looking_for = path.segments[path.segments.len() - 1].ident;
- visitor.reset(looking_for);
-
- match parent {
- hir::Node::Item(parent_item) => {
- hir::intravisit::walk_item(&mut visitor, parent_item);
- }
- hir::Node::Crate(m) => {
- hir::intravisit::walk_mod(
- &mut visitor,
- m,
- tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()),
- );
- }
- _ => break,
- }
- if let Some(i) = visitor.item {
- item = i;
- } else {
- break;
+ add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id));
}
}
+ attrs
}
fn filter_tokens_from_list(
@@ -2215,17 +2147,24 @@ fn filter_tokens_from_list(
/// * `doc(inline)`
/// * `doc(no_inline)`
/// * `doc(hidden)`
-fn add_without_unwanted_attributes(
- attrs: &mut Vec<ast::Attribute>,
- new_attrs: &[ast::Attribute],
+fn add_without_unwanted_attributes<'hir>(
+ attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>,
+ new_attrs: &'hir [ast::Attribute],
is_inline: bool,
+ import_parent: Option<DefId>,
) {
- // If it's `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
+ // If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
if !is_inline {
- attrs.extend_from_slice(new_attrs);
+ for attr in new_attrs {
+ attrs.push((Cow::Borrowed(attr), import_parent));
+ }
return;
}
for attr in new_attrs {
+ if matches!(attr.kind, ast::AttrKind::DocComment(..)) {
+ attrs.push((Cow::Borrowed(attr), import_parent));
+ continue;
+ }
let mut attr = attr.clone();
match attr.kind {
ast::AttrKind::Normal(ref mut normal) => {
@@ -2252,18 +2191,15 @@ fn add_without_unwanted_attributes(
)
});
args.tokens = TokenStream::new(tokens);
- attrs.push(attr);
+ attrs.push((Cow::Owned(attr), import_parent));
}
ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {
- attrs.push(attr);
- continue;
+ attrs.push((Cow::Owned(attr), import_parent));
}
}
}
}
- ast::AttrKind::DocComment(..) => {
- attrs.push(attr);
- }
+ _ => unreachable!(),
}
}
}
@@ -2318,16 +2254,17 @@ fn clean_maybe_renamed_item<'tcx>(
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
- // proc macros can have a name set by attributes
- ItemKind::Fn(ref sig, generics, body_id) => {
- clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
- }
- ItemKind::Macro(ref macro_def, _) => {
+ ItemKind::Macro(ref macro_def, MacroKind::Bang) => {
let ty_vis = cx.tcx.visibility(def_id);
MacroItem(Macro {
source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
})
}
+ ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
+ // proc macros can have a name set by attributes
+ ItemKind::Fn(ref sig, generics, body_id) => {
+ clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
+ }
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
let items = item_ids
.iter()
@@ -2350,26 +2287,28 @@ fn clean_maybe_renamed_item<'tcx>(
_ => unreachable!("not yet converted"),
};
- let mut import_attrs = Vec::new();
- let mut target_attrs = Vec::new();
- if let Some(import_id) = import_id &&
- let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id)
- {
- let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some();
- // Then we get all the various imports' attributes.
- get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline);
- add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline);
+ let target_attrs = inline::load_attrs(cx, def_id);
+ let attrs = if let Some(import_id) = import_id {
+ let is_inline = inline::load_attrs(cx, import_id.to_def_id())
+ .lists(sym::doc)
+ .get_word_attr(sym::inline)
+ .is_some();
+ let mut attrs =
+ get_all_import_attributes(cx, import_id, item.owner_id.def_id, is_inline);
+ add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None);
+ attrs
} else {
// We only keep the item's attributes.
- target_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
- }
+ target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
+ };
- let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id());
- let (attrs, cfg) = merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs));
+ let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
+ let attrs =
+ Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
let mut item =
Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg);
- item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id());
+ item.inline_stmt_id = import_id.map(|local| local.to_def_id());
vec![item]
})
}
@@ -2450,22 +2389,17 @@ fn clean_extern_crate<'tcx>(
Some(l) => attr::list_contains_name(&l, sym::inline),
None => false,
}
- });
+ })
+ && !cx.output_format.is_json();
let krate_owner_def_id = krate.owner_id.to_def_id();
if please_inline {
- let mut visited = DefIdSet::default();
-
- let res = Res::Def(DefKind::Mod, crate_def_id);
-
if let Some(items) = inline::try_inline(
cx,
- cx.tcx.parent_module(krate.hir_id()).to_def_id(),
- Some(krate_owner_def_id),
- res,
+ Res::Def(DefKind::Mod, crate_def_id),
name,
- Some(attrs),
- &mut visited,
+ Some((attrs, Some(krate_owner_def_id))),
+ &mut Default::default(),
) {
return items;
}
@@ -2589,17 +2523,13 @@ fn clean_use_statement_inner<'tcx>(
denied = true;
}
if !denied {
- let mut visited = DefIdSet::default();
let import_def_id = import.owner_id.to_def_id();
-
if let Some(mut items) = inline::try_inline(
cx,
- cx.tcx.parent_module(import.hir_id()).to_def_id(),
- Some(import_def_id),
path.res,
name,
- Some(attrs),
- &mut visited,
+ Some((attrs, Some(import_def_id))),
+ &mut Default::default(),
) {
items.push(Item::from_def_id_and_parts(
import_def_id,
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index dbbc25739..3c72b0bf9 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -49,11 +49,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP
equalities.retain(|(lhs, rhs, bound_params)| {
let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
- let bound_params = bound_params
- .into_iter()
- .map(|param| clean::GenericParamDef::lifetime(param.0))
- .collect();
- merge_bounds(cx, bounds, bound_params, trait_did, name, rhs)
+ merge_bounds(cx, bounds, bound_params.clone(), trait_did, name, rhs)
});
// And finally, let's reassemble everything
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 27d18aad7..6d2ce9e28 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1,5 +1,5 @@
+use std::borrow::Cow;
use std::cell::RefCell;
-use std::default::Default;
use std::hash::Hash;
use std::path::PathBuf;
use std::rc::Rc;
@@ -22,7 +22,7 @@ use rustc_hir::{BodyId, Mutability};
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility};
+use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
@@ -231,14 +231,6 @@ impl ExternalCrate {
hir::ItemKind::Mod(_) => {
as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
- hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.owner_id).is_public() =>
- {
- path.res
- .iter()
- .find_map(|res| as_keyword(res.expect_non_local()))
- .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
- }
_ => None,
}
})
@@ -256,38 +248,24 @@ impl ExternalCrate {
//
// Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an
- // item tagged with `#[doc(primitive)]` then we would also have to
+ // item tagged with `#[rustc_doc_primitive]` then we would also have to
// search the entirety of external modules for items tagged
- // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
+ // `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
//
// In order to keep the metadata load under control, the
- // `#[doc(primitive)]` feature is explicitly designed to only allow the
+ // `#[rustc_doc_primitive]` feature is explicitly designed to only allow the
// primitive tags to show up as the top level items in a crate.
//
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
let as_primitive = |res: Res<!>| {
- if let Res::Def(DefKind::Mod, def_id) = res {
- let mut prim = None;
- let meta_items = tcx
- .get_attrs(def_id, sym::doc)
- .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
- for meta in meta_items {
- if let Some(v) = meta.value_str() {
- if meta.has_name(sym::primitive) {
- prim = PrimitiveType::from_symbol(v);
- if prim.is_some() {
- break;
- }
- // FIXME: should warn on unknown primitives?
- }
- }
- }
- return prim.map(|p| (def_id, p));
- }
- None
+ let Res::Def(DefKind::Mod, def_id) = res else { return None };
+ tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| {
+ // FIXME: should warn on unknown primitives?
+ Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?))
+ })
};
if root.is_local() {
@@ -301,15 +279,6 @@ impl ExternalCrate {
hir::ItemKind::Mod(_) => {
as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
- hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.owner_id).is_public() =>
- {
- path.res
- .iter()
- .find_map(|res| as_primitive(res.expect_non_local()))
- // Pretend the primitive is local.
- .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
- }
_ => None,
}
})
@@ -482,10 +451,12 @@ impl Item {
pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
use crate::html::format::{href, link_tooltip};
- cx.cache()
+ let Some(links) = cx.cache()
.intra_doc_links
- .get(&self.item_id)
- .map_or(&[][..], |v| v.as_slice())
+ .get(&self.item_id) else {
+ return vec![]
+ };
+ links
.iter()
.filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| {
debug!(?id);
@@ -513,10 +484,12 @@ impl Item {
/// the link text, but does need to know which `[]`-bracketed names
/// are actually links.
pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
- cache
+ let Some(links) = cache
.intra_doc_links
- .get(&self.item_id)
- .map_or(&[][..], |v| v.as_slice())
+ .get(&self.item_id) else {
+ return vec![];
+ };
+ links
.iter()
.map(|ItemLink { link: s, link_text, .. }| RenderedLink {
original_text: s.clone(),
@@ -713,7 +686,7 @@ impl Item {
return None;
}
// Variants always inherit visibility
- VariantItem(..) => return None,
+ VariantItem(..) | ImplItem(..) => return None,
// Trait items inherit the trait's visibility
AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..)
| TyMethodItem(..) | MethodItem(..) => {
@@ -869,28 +842,13 @@ pub(crate) trait AttributesExt {
type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
where
Self: 'a;
+ type Attributes<'a>: Iterator<Item = &'a ast::Attribute>
+ where
+ Self: 'a;
fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
- fn span(&self) -> Option<rustc_span::Span>;
-
- fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
-}
-
-impl AttributesExt for [ast::Attribute] {
- type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
-
- fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
- self.iter()
- .filter(move |attr| attr.has_name(name))
- .filter_map(ast::Attribute::meta_item_list)
- .flatten()
- }
-
- /// Return the span of the first doc-comment, if it exists.
- fn span(&self) -> Option<rustc_span::Span> {
- self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
- }
+ fn iter<'a>(&'a self) -> Self::Attributes<'a>;
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
let sess = tcx.sess;
@@ -980,11 +938,48 @@ impl AttributesExt for [ast::Attribute] {
}
}
+impl AttributesExt for [ast::Attribute] {
+ type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
+ type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a;
+
+ fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
+ self.iter()
+ .filter(move |attr| attr.has_name(name))
+ .filter_map(ast::Attribute::meta_item_list)
+ .flatten()
+ }
+
+ fn iter<'a>(&'a self) -> Self::Attributes<'a> {
+ self.into_iter()
+ }
+}
+
+impl AttributesExt for [(Cow<'_, ast::Attribute>, Option<DefId>)] {
+ type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a
+ where Self: 'a;
+ type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a
+ where Self: 'a;
+
+ fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
+ AttributesExt::iter(self)
+ .filter(move |attr| attr.has_name(name))
+ .filter_map(ast::Attribute::meta_item_list)
+ .flatten()
+ }
+
+ fn iter<'a>(&'a self) -> Self::Attributes<'a> {
+ self.into_iter().map(move |(attr, _)| match attr {
+ Cow::Borrowed(attr) => *attr,
+ Cow::Owned(attr) => attr,
+ })
+ }
+}
+
pub(crate) trait NestedAttributesExt {
/// Returns `true` if the attribute list contains a specific `word`
fn has_word(self, word: Symbol) -> bool
where
- Self: std::marker::Sized,
+ Self: Sized,
{
<Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
}
@@ -1014,7 +1009,7 @@ pub(crate) fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
/// A link that has not yet been rendered.
///
/// This link will be turned into a rendered link by [`Item::links`].
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct ItemLink {
/// The original link written in the markdown
pub(crate) link: Box<str>,
@@ -1213,9 +1208,9 @@ impl Lifetime {
#[derive(Clone, Debug)]
pub(crate) enum WherePredicate {
- BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
+ BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
- EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<Lifetime> },
+ EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<GenericParamDef> },
}
impl WherePredicate {
@@ -1227,7 +1222,7 @@ impl WherePredicate {
}
}
- pub(crate) fn get_bound_params(&self) -> Option<&[Lifetime]> {
+ pub(crate) fn get_bound_params(&self) -> Option<&[GenericParamDef]> {
match self {
Self::BoundPredicate { bound_params, .. } | Self::EqPredicate { bound_params, .. } => {
Some(bound_params)
@@ -1241,7 +1236,7 @@ impl WherePredicate {
pub(crate) enum GenericParamDefKind {
Lifetime { outlives: Vec<Lifetime> },
Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
- Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
+ Const { ty: Box<Type>, default: Option<Box<String>> },
}
impl GenericParamDefKind {
@@ -1471,27 +1466,68 @@ impl Type {
result
}
- /// Check if two types are "potentially the same".
+ pub(crate) fn is_borrowed_ref(&self) -> bool {
+ matches!(self, Type::BorrowedRef { .. })
+ }
+
+ /// Check if two types are "the same" for documentation purposes.
+ ///
/// This is different from `Eq`, because it knows that things like
/// `Placeholder` are possible matches for everything.
- pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
- match (self, other) {
+ ///
+ /// This relation is not commutative when generics are involved:
+ ///
+ /// ```ignore(private)
+ /// # // see types/tests.rs:is_same_generic for the real test
+ /// use rustdoc::format::cache::Cache;
+ /// use rustdoc::clean::types::{Type, PrimitiveType};
+ /// let cache = Cache::new(false);
+ /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
+ /// let unit = Type::Primitive(PrimitiveType::Unit);
+ /// assert!(!generic.is_same(&unit, &cache));
+ /// assert!(unit.is_same(&generic, &cache));
+ /// ```
+ ///
+ /// An owned type is also the same as its borrowed variants (this is commutative),
+ /// but `&T` is not the same as `&mut T`.
+ pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
+ // Strip the references so that it can compare the actual types, unless both are references.
+ // If both are references, leave them alone and compare the mutabilities later.
+ let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
+ (self.without_borrowed_ref(), other.without_borrowed_ref())
+ } else {
+ (self, other)
+ };
+ match (self_cleared, other_cleared) {
// Recursive cases.
(Type::Tuple(a), Type::Tuple(b)) => {
- a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache))
+ a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
}
- (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache),
- (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache),
+ (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
+ (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
(Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
- mutability == b_mutability && type_.is_same(b_type_, cache)
+ mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
}
(
Type::BorrowedRef { mutability, type_, .. },
Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
- ) => mutability == b_mutability && type_.is_same(b_type_, cache),
- // Placeholders and generics are equal to all other types.
+ ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
+ // Placeholders are equal to all other types.
(Type::Infer, _) | (_, Type::Infer) => true,
- (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+ // Generics match everything on the right, but not on the left.
+ // If both sides are generic, this returns true.
+ (_, Type::Generic(_)) => true,
+ (Type::Generic(_), _) => false,
+ // Paths account for both the path itself and its generics.
+ (Type::Path { path: a }, Type::Path { path: b }) => {
+ a.def_id() == b.def_id()
+ && a.generics()
+ .zip(b.generics())
+ .map(|(ag, bg)| {
+ ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
+ })
+ .unwrap_or(true)
+ }
// Other cases, such as primitives, just use recursion.
(a, b) => a
.def_id(cache)
@@ -1782,13 +1818,17 @@ impl PrimitiveType {
}
}
- /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
+ /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
/// Panics if there is no such module.
///
- /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
- /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
- /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
- /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
+ /// This gives precedence to primitives defined in the current crate, and deprioritizes
+ /// primitives defined in `core`,
+ /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
+ /// will be picked.
+ ///
+ /// In particular, if a crate depends on both `std` and another crate that also defines
+ /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
+ /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
PRIMITIVE_LOCATIONS.get_or_init(|| {
@@ -1978,7 +2018,7 @@ impl Variant {
#[derive(Clone, Debug)]
pub(crate) struct Discriminant {
- // In the case of cross crate re-exports, we don't have the nessesary information
+ // In the case of cross crate re-exports, we don't have the necessary information
// to reconstruct the expression of the discriminant, only the value.
pub(super) expr: Option<BodyId>,
pub(super) value: DefId,
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
index 20627c2cf..d8c91a968 100644
--- a/src/librustdoc/clean/types/tests.rs
+++ b/src/librustdoc/clean/types/tests.rs
@@ -10,7 +10,7 @@ use rustc_span::symbol::Symbol;
fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
vec![DocFragment {
span: DUMMY_SP,
- parent_module: None,
+ item_id: None,
doc: Symbol::intern(s),
kind: DocFragmentKind::SugaredDoc,
indent: 0,
@@ -69,3 +69,14 @@ fn should_not_trim() {
run_test("\t line1 \n\t line2", "line1 \nline2");
run_test(" \tline1 \n \tline2", "line1 \nline2");
}
+
+#[test]
+fn is_same_generic() {
+ use crate::clean::types::{PrimitiveType, Type};
+ use crate::formats::cache::Cache;
+ let cache = Cache::new(false);
+ let generic = Type::Generic(rustc_span::symbol::sym::Any);
+ let unit = Type::Primitive(PrimitiveType::Unit);
+ assert!(!generic.is_doc_subtype_of(&unit, &cache));
+ assert!(unit.is_doc_subtype_of(&generic, &cache));
+}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c9c1c2c45..cca50df0d 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -17,7 +17,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
use std::mem;
@@ -195,12 +195,12 @@ pub(crate) fn build_deref_target_impls(
if let Some(prim) = target.primitive_type() {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
for did in prim.impls(tcx).filter(|did| !did.is_local()) {
- inline::build_impl(cx, None, did, None, ret);
+ inline::build_impl(cx, did, None, ret);
}
} else if let Type::Path { path } = target {
let did = path.def_id();
if !did.is_local() {
- inline::build_impls(cx, None, did, None, ret);
+ inline::build_impls(cx, did, None, ret);
}
}
}