diff options
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r-- | src/librustdoc/clean/auto_trait.rs | 20 | ||||
-rw-r--r-- | src/librustdoc/clean/blanket_impl.rs | 35 | ||||
-rw-r--r-- | src/librustdoc/clean/cfg.rs | 31 | ||||
-rw-r--r-- | src/librustdoc/clean/inline.rs | 61 | ||||
-rw-r--r-- | src/librustdoc/clean/mod.rs | 464 | ||||
-rw-r--r-- | src/librustdoc/clean/render_macro_matchers.rs | 14 | ||||
-rw-r--r-- | src/librustdoc/clean/simplify.rs | 39 | ||||
-rw-r--r-- | src/librustdoc/clean/types.rs | 117 | ||||
-rw-r--r-- | src/librustdoc/clean/types/tests.rs | 2 | ||||
-rw-r--r-- | src/librustdoc/clean/utils.rs | 123 |
10 files changed, 588 insertions, 318 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 92bae5516..a06f31a93 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -46,7 +46,7 @@ where let tcx = self.cx.tcx; let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty])); if !self.cx.generated_synthetics.insert((ty, trait_def_id)) { - debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); + debug!("get_auto_trait_impl_for({trait_ref:?}): already generated, aborting"); return None; } @@ -137,10 +137,10 @@ where pub(crate) fn get_auto_trait_impls(&mut self, item_def_id: DefId) -> Vec<Item> { let tcx = self.cx.tcx; let param_env = tcx.param_env(item_def_id); - let ty = tcx.type_of(item_def_id).subst_identity(); + let ty = tcx.type_of(item_def_id).instantiate_identity(); let f = auto_trait::AutoTraitFinder::new(tcx); - debug!("get_auto_trait_impls({:?})", ty); + debug!("get_auto_trait_impls({ty:?})"); let auto_traits: Vec<_> = self.cx.auto_traits.to_vec(); let mut auto_traits: Vec<Item> = auto_traits .into_iter() @@ -163,9 +163,9 @@ where fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime { region_name(region) .map(|name| { - names_map.get(&name).unwrap_or_else(|| { - panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region) - }) + names_map + .get(&name) + .unwrap_or_else(|| panic!("Missing lifetime with name {name:?} for {region:?}")) }) .unwrap_or(&Lifetime::statik()) .clone() @@ -372,7 +372,7 @@ where let output = output.as_ref().cloned().map(Box::new); if old_output.is_some() && old_output != output { - panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output); + panic!("Output mismatch for {ty:?} {old_output:?} {output:?}"); } let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; @@ -462,7 +462,7 @@ where ); let mut generic_params = raw_generics.params; - debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params); + debug!("param_env_to_generics({item_def_id:?}): generic_params={generic_params:?}"); let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); @@ -623,7 +623,7 @@ where // loop ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone()); } - _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), + _ => panic!("Unexpected LHS {lhs:?} for {item_def_id:?}"), } } }; @@ -710,7 +710,7 @@ where /// involved (impls rarely have more than a few bounds) means that it /// shouldn't matter in practice. fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) { - vec.sort_by_cached_key(|x| format!("{:?}", x)) + vec.sort_by_cached_key(|x| format!("{x:?}")) } fn is_fn_trait(&self, path: &Path) -> bool { diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index a36041588..dad2aa406 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -17,7 +17,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let param_env = cx.tcx.param_env(item_def_id); let ty = cx.tcx.type_of(item_def_id); - trace!("get_blanket_impls({:?})", ty); + trace!("get_blanket_impls({ty:?})"); let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) @@ -38,18 +38,22 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { continue; } let infcx = cx.tcx.infer_ctxt().build(); - let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); - let impl_ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder::bind(param_env).subst(infcx.tcx, substs); + let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); + let impl_ty = ty.instantiate(infcx.tcx, args); + let param_env = EarlyBinder::bind(param_env).instantiate(infcx.tcx, args); - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args); // Require the type the impl is implemented on to match // our type, and ignore the impl if there was a mismatch. - let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else { - continue - }; + 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; // FIXME(eddyb) ignoring `obligations` might cause false positives. drop(obligations); @@ -63,12 +67,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let predicates = cx .tcx .predicates_of(impl_def_id) - .instantiate(cx.tcx, impl_substs) + .instantiate(cx.tcx, impl_args) .predicates .into_iter() .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx))); for predicate in predicates { - debug!("testing predicate {:?}", predicate); + debug!("testing predicate {predicate:?}"); let obligation = traits::Obligation::new( infcx.tcx, traits::ObligationCause::dummy(), @@ -104,11 +108,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // the post-inference `trait_ref`, as it's more accurate. trait_: Some(clean_trait_ref_with_bindings( cx, - ty::Binder::dummy(trait_ref.subst_identity()), + ty::Binder::dummy(trait_ref.instantiate_identity()), ThinVec::new(), )), for_: clean_middle_ty( - ty::Binder::dummy(ty.subst_identity()), + ty::Binder::dummy(ty.instantiate_identity()), cx, None, None, @@ -117,11 +121,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .tcx .associated_items(impl_def_id) .in_definition_order() - .map(|x| clean_middle_assoc_item(x, cx)) + .filter(|item| !item.is_impl_trait_in_trait()) + .map(|item| clean_middle_assoc_item(item, cx)) .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(Box::new(clean_middle_ty( - ty::Binder::dummy(trait_ref.subst_identity().self_ty()), + ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()), cx, None, None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 5177cffe6..ab5aec12f 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -434,9 +434,9 @@ impl<'a> fmt::Display for Display<'a> { } if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { if self.1.is_html() { - write!(fmt, "<code>{}</code>", feat)?; + write!(fmt, "<code>{feat}</code>")?; } else { - write!(fmt, "`{}`", feat)?; + write!(fmt, "`{feat}`")?; } } else { write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; @@ -471,9 +471,9 @@ impl<'a> fmt::Display for Display<'a> { } if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { if self.1.is_html() { - write!(fmt, "<code>{}</code>", feat)?; + write!(fmt, "<code>{feat}</code>")?; } else { - write!(fmt, "`{}`", feat)?; + write!(fmt, "`{feat}`")?; } } else { write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?; @@ -519,8 +519,11 @@ impl<'a> fmt::Display for Display<'a> { "asmjs" => "JavaScript", "loongarch64" => "LoongArch LA64", "m68k" => "M68k", + "csky" => "CSKY", "mips" => "MIPS", + "mips32r6" => "MIPS Release 6", "mips64" => "MIPS-64", + "mips64r6" => "MIPS-64 Release 6", "msp430" => "MSP430", "powerpc" => "PowerPC", "powerpc64" => "PowerPC-64", @@ -549,21 +552,21 @@ impl<'a> fmt::Display for Display<'a> { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian), - (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits), + (sym::target_endian, Some(endian)) => return write!(fmt, "{endian}-endian"), + (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{bits}-bit"), (sym::target_feature, Some(feat)) => match self.1 { Format::LongHtml => { - return write!(fmt, "target feature <code>{}</code>", feat); + return write!(fmt, "target feature <code>{feat}</code>"); } - Format::LongPlain => return write!(fmt, "target feature `{}`", feat), - Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat), + Format::LongPlain => return write!(fmt, "target feature `{feat}`"), + Format::ShortHtml => return write!(fmt, "<code>{feat}</code>"), }, (sym::feature, Some(feat)) => match self.1 { Format::LongHtml => { - return write!(fmt, "crate feature <code>{}</code>", feat); + return write!(fmt, "crate feature <code>{feat}</code>"); } - Format::LongPlain => return write!(fmt, "crate feature `{}`", feat), - Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat), + Format::LongPlain => return write!(fmt, "crate feature `{feat}`"), + Format::ShortHtml => return write!(fmt, "<code>{feat}</code>"), }, _ => "", }; @@ -578,12 +581,12 @@ impl<'a> fmt::Display for Display<'a> { Escape(v.as_str()) ) } else { - write!(fmt, r#"`{}="{}"`"#, name, v) + write!(fmt, r#"`{name}="{v}"`"#) } } else if self.1.is_html() { write!(fmt, "<code>{}</code>", Escape(name.as_str())) } else { - write!(fmt, "`{}`", name) + write!(fmt, "`{name}`") } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 870cfa930..cac211307 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,9 +9,10 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdSet, LocalModDefId}; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -49,7 +50,7 @@ pub(crate) fn try_inline( } let mut ret = Vec::new(); - debug!("attrs={:?}", attrs); + debug!("attrs={attrs:?}"); let attrs_without_docs = attrs.map(|(attrs, def_id)| { (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id) @@ -78,7 +79,7 @@ pub(crate) fn try_inline( build_impls(cx, did, attrs_without_docs, &mut ret); clean::UnionItem(build_union(cx, did)) } - Res::Def(DefKind::TyAlias, did) => { + Res::Def(DefKind::TyAlias { .. }, did) => { record_extern_fqn(cx, did, ItemType::Typedef); build_impls(cx, did, attrs_without_docs, &mut ret); clean::TypedefItem(build_type_alias(cx, did)) @@ -137,9 +138,10 @@ pub(crate) fn try_inline( pub(crate) fn try_inline_glob( cx: &mut DocContext<'_>, res: Res, - current_mod: LocalDefId, + current_mod: LocalModDefId, visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, + import: &hir::Item<'_>, ) -> Option<Vec<clean::Item>> { let did = res.opt_def_id()?; if did.is_local() { @@ -152,12 +154,20 @@ pub(crate) fn try_inline_glob( // reexported by the glob, e.g. because they are shadowed by something else. let reexports = cx .tcx - .module_children_local(current_mod) + .module_children_local(current_mod.to_local_def_id()) .iter() .filter(|child| !child.reexport_chain.is_empty()) .filter_map(|child| child.res.opt_def_id()) .collect(); - let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports)); + let attrs = cx.tcx.hir().attrs(import.hir_id()); + let mut items = build_module_items( + cx, + did, + visited, + inlined_names, + Some(&reexports), + Some((attrs, Some(import.owner_id.def_id.to_def_id()))), + ); items.retain(|item| { if let Some(name) = item.name { // If an item with the same type and name already exists, @@ -190,7 +200,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT let fqn = if let ItemType::Macro = kind { // Check to see if it is a macro 2.0 or built-in macro if matches!( - CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.sess()), + CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx), LoadedMacro::MacroDef(def, _) if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules) @@ -215,6 +225,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean .tcx .associated_items(did) .in_definition_order() + .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| clean_middle_assoc_item(item, cx)) .collect(); @@ -226,7 +237,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean } fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> { - let sig = cx.tcx.fn_sig(did).subst_identity(); + let sig = cx.tcx.fn_sig(did).instantiate_identity(); let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var { ty::BoundVariableKind::Region(ty::BrNamed(_, name)) if name != kw::UnderscoreLifetime => { @@ -279,7 +290,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> { let predicates = cx.tcx.explicit_predicates_of(did); let type_ = clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), cx, Some(did), None, @@ -314,9 +325,8 @@ pub(crate) fn build_impls( // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { - use rustc_middle::ty::fast_reject::SimplifiedType::*; let type_ = - if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; + if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) }; for &did in tcx.incoherent_impls(type_) { build_impl(cx, did, attrs, ret); } @@ -391,7 +401,7 @@ pub(crate) fn build_impl( let for_ = match &impl_item { Some(impl_) => clean_ty(impl_.self_ty, cx), None => clean_middle_ty( - ty::Binder::dummy(tcx.type_of(did).subst_identity()), + ty::Binder::dummy(tcx.type_of(did).instantiate_identity()), cx, Some(did), None, @@ -459,6 +469,7 @@ pub(crate) fn build_impl( None => ( tcx.associated_items(did) .in_definition_order() + .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| { // If this is a trait impl, filter out associated items whose corresponding item // in the associated trait is marked `doc(hidden)`. @@ -473,7 +484,7 @@ pub(crate) fn build_impl( associated_trait.def_id, ) .unwrap(); // corresponding associated item has to exist - !tcx.is_doc_hidden(trait_item.def_id) + document_hidden || !tcx.is_doc_hidden(trait_item.def_id) } else { item.visibility(tcx).is_public() } @@ -496,7 +507,7 @@ pub(crate) fn build_impl( let mut stack: Vec<&Type> = vec![&for_]; if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { - if tcx.is_doc_hidden(did) { + if !document_hidden && tcx.is_doc_hidden(did) { return; } } @@ -505,7 +516,7 @@ pub(crate) fn build_impl( } while let Some(ty) = stack.pop() { - if let Some(did) = ty.def_id(&cx.cache) && tcx.is_doc_hidden(did) { + if let Some(did) = ty.def_id(&cx.cache) && !document_hidden && tcx.is_doc_hidden(did) { return; } if let Some(generics) = ty.generics() { @@ -518,7 +529,7 @@ pub(crate) fn build_impl( } let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); - trace!("merged_attrs={:?}", merged_attrs); + trace!("merged_attrs={merged_attrs:?}"); trace!( "build_impl: impl {:?} for {:?}", @@ -547,7 +558,7 @@ pub(crate) fn build_impl( } fn build_module(cx: &mut DocContext<'_>, did: DefId, visited: &mut DefIdSet) -> clean::Module { - let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None); + let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None, None); let span = clean::Span::new(cx.tcx.def_span(did)); clean::Module { items, span } @@ -559,6 +570,7 @@ fn build_module_items( visited: &mut DefIdSet, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, allowed_def_ids: Option<&DefIdSet>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, ) -> Vec<clean::Item> { let mut items = Vec::new(); @@ -613,7 +625,7 @@ fn build_module_items( cfg: None, inline_stmt_id: None, }); - } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) { + } else if let Some(i) = try_inline(cx, res, item.ident.name, attrs, visited) { items.extend(i) } } @@ -632,13 +644,18 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { + let mut generics = + clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + clean::simplify::move_bounds_to_generic_parameters(&mut generics); + clean::Constant { type_: clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), cx, Some(def_id), None, ), + generics: Box::new(generics), kind: clean::ConstantKind::Extern { def_id }, } } @@ -646,7 +663,7 @@ fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { type_: clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), cx, Some(did), None, @@ -663,7 +680,7 @@ fn build_macro( import_def_id: Option<DefId>, macro_kind: MacroKind, ) -> clean::ItemKind { - match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { + match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { LoadedMacro::MacroDef(item_def, _) => match macro_kind { MacroKind::Bang => { if let ast::ItemKind::MacroDef(ref def) = item_def.kind { @@ -764,7 +781,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { cx.active_extern_traits.insert(did); } - debug!("record_extern_trait: {:?}", did); + debug!("record_extern_trait: {did:?}"); let trait_ = build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, trait_); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8ad1ed095..c9a05460b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -24,7 +24,6 @@ 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, EarlyBinder, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -54,7 +53,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< let mut inserted = FxHashSet::default(); items.extend(doc.foreigns.iter().map(|(item, renamed)| { let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); - if let Some(name) = item.name && !item.is_doc_hidden() { + if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) { inserted.insert((item.type_(), name)); } item @@ -64,7 +63,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< return None; } let item = clean_doc_module(x, cx); - if item.is_doc_hidden() { + if !cx.render_options.document_hidden && item.is_doc_hidden() { // Hidden modules are stripped at a later stage. // If a hidden module has the same name as a visible one, we want // to keep both of them around. @@ -85,12 +84,25 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id); for item in &v { - if let Some(name) = item.name && !item.is_doc_hidden() { + if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) { inserted.insert((item.type_(), name)); } } v })); + items.extend(doc.inlined_foreigns.iter().flat_map(|((_, renamed), (res, local_import_id))| { + let Some(def_id) = res.opt_def_id() else { return Vec::new() }; + let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id)); + let import = cx.tcx.hir().expect_item(*local_import_id); + match import.kind { + hir::ItemKind::Use(path, kind) => { + let hir::UsePath { segments, span, .. } = *path; + let path = hir::Path { segments, res: *res, span }; + clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default()) + } + _ => unreachable!(), + } + })); items.extend(doc.items.values().flat_map(|(item, renamed, _)| { // Now we actually lower the imports, skipping everything else. if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { @@ -120,25 +132,31 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< }); let kind = ModuleItem(Module { items, span }); - generate_item_with_correct_attrs(cx, kind, doc.def_id, doc.name, doc.import_id, doc.renamed) + generate_item_with_correct_attrs( + cx, + kind, + doc.def_id.to_def_id(), + doc.name, + doc.import_id, + doc.renamed, + ) } fn generate_item_with_correct_attrs( cx: &mut DocContext<'_>, kind: ItemKind, - local_def_id: LocalDefId, + def_id: DefId, name: Symbol, import_id: Option<LocalDefId>, renamed: Option<Symbol>, ) -> Item { - let def_id = local_def_id.to_def_id(); 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, local_def_id, is_inline); + let mut attrs = get_all_import_attributes(cx, import_id, def_id, is_inline); add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); attrs } else { @@ -197,11 +215,11 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( ) -> Path { let kind = cx.tcx.def_kind(trait_ref.def_id()).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { - span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {:?}", kind); + span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}"); } inline::record_extern_fqn(cx, trait_ref.def_id(), kind); let path = - external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.substs)); + external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.args)); debug!(?trait_ref); @@ -239,7 +257,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> | rbv::ResolvedArg::Free(_, node_id), ) = def { - if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() { + if let Some(lt) = cx.args.get(&node_id).and_then(|p| p.as_lt()).cloned() { return lt; } } @@ -250,11 +268,12 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'t let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id(); Constant { type_: clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), cx, Some(def_id), None, ), + generics: Box::new(Generics::default()), kind: ConstantKind::Anonymous { body: constant.value.body }, } } @@ -266,6 +285,7 @@ pub(crate) fn clean_middle_const<'tcx>( // FIXME: instead of storing the stringified expression, store `self` directly instead. Constant { type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None), + generics: Box::new(Generics::default()), kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() }, } } @@ -284,7 +304,7 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life | ty::ReError(_) | ty::RePlaceholder(..) | ty::ReErased => { - debug!("cannot clean region {:?}", region); + debug!("cannot clean region {region:?}"); None } } @@ -350,9 +370,8 @@ fn clean_poly_trait_predicate<'tcx>( cx: &mut DocContext<'tcx>, ) -> Option<WherePredicate> { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst - && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() - { + // FIXME(effects) check constness + if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() { return None; } @@ -442,7 +461,7 @@ fn clean_projection<'tcx>( let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) - .subst_iter_copied(cx.tcx, ty.skip_binder().substs) + .iter_instantiated_copied(cx.tcx, ty.skip_binder().args) .map(|(pred, _)| pred) .collect::<Vec<_>>(); return clean_middle_opaque_bounds(cx, bounds); @@ -481,9 +500,9 @@ fn projection_to_path_segment<'tcx>( PathSegment { name: item.name, args: GenericArgs::AngleBracketed { - args: substs_to_args( + args: ty_args_to_args( cx, - ty.map_bound(|ty| &ty.substs[generics.parent_count..]), + ty.map_bound(|ty| &ty.args[generics.parent_count..]), false, None, ) @@ -504,7 +523,7 @@ fn clean_generic_param_def<'tcx>( ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { Some(clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(def.def_id).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(def.def_id).instantiate_identity()), cx, Some(def.def_id), None, @@ -538,7 +557,7 @@ fn clean_generic_param_def<'tcx>( )), default: match has_default { true => Some(Box::new( - cx.tcx.const_param_default(def.def_id).subst_identity().to_string(), + cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string(), )), false => None, }, @@ -786,10 +805,10 @@ fn clean_ty_generics<'tcx>( let where_predicates = preds .predicates .iter() - .flat_map(|(p, _)| { + .flat_map(|(pred, _)| { let mut projection = None; let param_idx = (|| { - let bound_p = p.kind(); + let bound_p = pred.kind(); match bound_p.skip_binder() { ty::ClauseKind::Trait(pred) => { if let ty::Param(param) = pred.self_ty().kind() { @@ -814,33 +833,26 @@ fn clean_ty_generics<'tcx>( })(); if let Some(param_idx) = param_idx - && let Some(b) = impl_trait.get_mut(¶m_idx.into()) + && let Some(bounds) = impl_trait.get_mut(¶m_idx.into()) { - let p: WherePredicate = clean_predicate(*p, cx)?; + let pred = clean_predicate(*pred, cx)?; - b.extend( - p.get_bounds() + bounds.extend( + pred.get_bounds() .into_iter() .flatten() .cloned() - .filter(|b| !b.is_sized_bound(cx)), ); - let proj = projection.map(|p| { - ( - clean_projection(p.map_bound(|p| p.projection_ty), cx, None), - p.map_bound(|p| p.term), - ) - }); - if let Some(((_, trait_did, name), rhs)) = proj - .as_ref() - .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs))) + if let Some(proj) = projection + && let lhs = clean_projection(proj.map_bound(|p| p.projection_ty), cx, None) + && let Some((_, trait_did, name)) = lhs.projection() { impl_trait_proj.entry(param_idx).or_default().push(( trait_did, name, - *rhs, - p.get_bound_params() + proj.map_bound(|p| p.term), + pred.get_bound_params() .into_iter() .flatten() .cloned() @@ -851,13 +863,32 @@ fn clean_ty_generics<'tcx>( return None; } - Some(p) + Some(pred) }) .collect::<Vec<_>>(); for (param, mut bounds) in impl_trait { + let mut has_sized = false; + bounds.retain(|b| { + if b.is_sized_bound(cx) { + has_sized = true; + false + } else { + true + } + }); + if !has_sized { + bounds.push(GenericBound::maybe_sized(cx)); + } + // Move trait bounds to the front. - bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..))); + bounds.sort_by_key(|b| !b.is_trait_bound()); + + // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`). + // Since all potential trait bounds are at the front we can just check the first bound. + if bounds.first().map_or(true, |b| !b.is_trait_bound()) { + bounds.insert(0, GenericBound::sized(cx)); + } let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() }; if let Some(proj) = impl_trait_proj.remove(&idx) { @@ -879,7 +910,7 @@ fn clean_ty_generics<'tcx>( // implicit `Sized` bound unless removed with `?Sized`. // However, in the list of where-predicates below, `Sized` appears like a // normal bound: It's either present (the type is sized) or - // absent (the type is unsized) but never *maybe* (i.e. `?Sized`). + // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`). // // This is unsuitable for rendering. // Thus, as a first step remove all `Sized` bounds that should be implicit. @@ -890,8 +921,8 @@ fn clean_ty_generics<'tcx>( let mut sized_params = FxHashSet::default(); where_predicates.retain(|pred| { if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred - && *g != kw::SelfUpper - && bounds.iter().any(|b| b.is_sized_bound(cx)) + && *g != kw::SelfUpper + && bounds.iter().any(|b| b.is_sized_bound(cx)) { sized_params.insert(*g); false @@ -1158,11 +1189,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext let local_did = trait_item.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match trait_item.kind { - hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( - clean_ty(ty, cx), - ConstantKind::Local { def_id: local_did, body: default }, - ), - hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), + hir::TraitItemKind::Const(ty, Some(default)) => { + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + AssocConstItem( + Box::new(generics), + clean_ty(ty, cx), + ConstantKind::Local { def_id: local_did, body: default }, + ) + } + hir::TraitItemKind::Const(ty, None) => { + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + TyAssocConstItem(Box::new(generics), clean_ty(ty, cx)) + } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); MethodItem(m, None) @@ -1207,8 +1245,9 @@ pub(crate) fn clean_impl_item<'tcx>( cx.with_param_env(local_did, |cx| { let inner = match impl_.kind { hir::ImplItemKind::Const(ty, expr) => { + let generics = clean_generics(impl_.generics, cx); let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(clean_ty(ty, cx), default) + AssocConstItem(Box::new(generics), clean_ty(ty, cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); @@ -1243,24 +1282,31 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let kind = match assoc_item.kind { ty::AssocKind::Const => { let ty = clean_middle_ty( - ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()), + ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()), cx, Some(assoc_item.def_id), None, ); + let mut generics = Box::new(clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + tcx.explicit_predicates_of(assoc_item.def_id), + )); + simplify::move_bounds_to_generic_parameters(&mut generics); + let provided = match assoc_item.container { ty::ImplContainer => true, ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(), }; if provided { - AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id }) + AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id }) } else { - TyAssocConstItem(ty) + TyAssocConstItem(generics, ty) } } ty::AssocKind::Fn => { - let sig = tcx.fn_sig(assoc_item.def_id).subst_identity(); + let sig = tcx.fn_sig(assoc_item.def_id).instantiate_identity(); let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var { ty::BoundVariableKind::Region(ty::BrNamed(_, name)) @@ -1283,7 +1329,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( if assoc_item.fn_has_self_parameter { let self_ty = match assoc_item.container { - ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)).subst_identity(), + ty::ImplContainer => { + tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity() + } ty::TraitContainer => tcx.types.self_param, }; let self_arg_ty = sig.input(0).skip_binder(); @@ -1339,7 +1387,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; if let ty::TraitContainer = assoc_item.container { let bounds = - tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); + tcx.explicit_item_bounds(assoc_item.def_id).instantiate_identity_iter_copied(); predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); } let mut generics = clean_ty_generics( @@ -1347,34 +1395,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, ); - // Move bounds that are (likely) directly attached to the parameters of the - // (generic) associated type from the where clause to the respective parameter. - // There is no guarantee that this is what the user actually wrote but we have - // no way of knowing. - let mut where_predicates = ThinVec::new(); - for mut pred in generics.where_predicates { - if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) - { - param_bounds.append(bounds); - } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Lifetime { outlives: param_bounds }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) - { - param_bounds.extend(bounds.drain(..).map(|bound| match bound { - GenericBound::Outlives(lifetime) => lifetime, - _ => unreachable!(), - })); - } else { - where_predicates.push(pred); - } - } - generics.where_predicates = where_predicates; + simplify::move_bounds_to_generic_parameters(&mut generics); if let ty::TraitContainer = assoc_item.container { // Move bounds that are (likely) directly attached to the associated type @@ -1442,7 +1463,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( AssocTypeItem( Box::new(Typedef { type_: clean_middle_ty( - ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()), + ty::Binder::dummy( + tcx.type_of(assoc_item.def_id).instantiate_identity(), + ), cx, Some(assoc_item.def_id), None, @@ -1459,7 +1482,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( AssocTypeItem( Box::new(Typedef { type_: clean_middle_ty( - ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()), + ty::Binder::dummy( + tcx.type_of(assoc_item.def_id).instantiate_identity(), + ), cx, Some(assoc_item.def_id), None, @@ -1478,14 +1503,127 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) } +fn first_non_private_clean_path<'tcx>( + cx: &mut DocContext<'tcx>, + path: &hir::Path<'tcx>, + new_path_segments: &'tcx [hir::PathSegment<'tcx>], + new_path_span: rustc_span::Span, +) -> Path { + let new_hir_path = + hir::Path { segments: new_path_segments, res: path.res, span: new_path_span }; + let mut new_clean_path = clean_path(&new_hir_path, cx); + // In here we need to play with the path data one last time to provide it the + // missing `args` and `res` of the final `Path` we get, which, since it comes + // from a re-export, doesn't have the generics that were originally there, so + // we add them by hand. + if let Some(path_last) = path.segments.last().as_ref() + && let Some(new_path_last) = new_clean_path.segments[..].last_mut() + && let Some(path_last_args) = path_last.args.as_ref() + && path_last.args.is_some() + { + assert!(new_path_last.args.is_empty()); + new_path_last.args = clean_generic_args(path_last_args, cx); + } + new_clean_path +} + +/// The goal of this function is to return the first `Path` which is not private (ie not private +/// or `doc(hidden)`). If it's not possible, it'll return the "end type". +/// +/// If the path is not a re-export or is public, it'll return `None`. +fn first_non_private<'tcx>( + cx: &mut DocContext<'tcx>, + hir_id: hir::HirId, + path: &hir::Path<'tcx>, +) -> Option<Path> { + let target_def_id = path.res.opt_def_id()?; + let (parent_def_id, ident) = match &path.segments[..] { + [] => return None, + // Relative paths are available in the same scope as the owner. + [leaf] => (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident), + // So are self paths. + [parent, leaf] if parent.ident.name == kw::SelfLower => { + (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident) + } + // Crate paths are not. We start from the crate root. + [parent, leaf] if matches!(parent.ident.name, kw::Crate | kw::PathRoot) => { + (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident) + } + [parent, leaf] if parent.ident.name == kw::Super => { + let parent_mod = cx.tcx.parent_module(hir_id); + if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod.to_local_def_id()) { + (super_parent, leaf.ident) + } else { + // If we can't find the parent of the parent, then the parent is already the crate. + (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident) + } + } + // Absolute paths are not. We start from the parent of the item. + [.., parent, leaf] => (parent.res.opt_def_id()?.as_local()?, leaf.ident), + }; + let hir = cx.tcx.hir(); + // First we try to get the `DefId` of the item. + for child in + cx.tcx.module_children_local(parent_def_id).iter().filter(move |c| c.ident == ident) + { + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res { + continue; + } + + if let Some(def_id) = child.res.opt_def_id() && target_def_id == def_id { + let mut last_path_res = None; + 'reexps: for reexp in child.reexport_chain.iter() { + if let Some(use_def_id) = reexp.id() && + let Some(local_use_def_id) = use_def_id.as_local() && + let Some(hir::Node::Item(item)) = hir.find_by_def_id(local_use_def_id) && + !item.ident.name.is_empty() && + let hir::ItemKind::Use(path, _) = item.kind + { + for res in &path.res { + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res { + continue; + } + if (cx.render_options.document_hidden || + !cx.tcx.is_doc_hidden(use_def_id)) && + // We never check for "cx.render_options.document_private" + // because if a re-export is not fully public, it's never + // documented. + cx.tcx.local_visibility(local_use_def_id).is_public() { + break 'reexps; + } + last_path_res = Some((path, res)); + continue 'reexps; + } + } + } + if !child.reexport_chain.is_empty() { + // So in here, we use the data we gathered from iterating the reexports. If + // `last_path_res` is set, it can mean two things: + // + // 1. We found a public reexport. + // 2. We didn't find a public reexport so it's the "end type" path. + if let Some((new_path, _)) = last_path_res { + return Some(first_non_private_clean_path(cx, path, new_path.segments, new_path.span)); + } + // If `last_path_res` is `None`, it can mean two things: + // + // 1. The re-export is public, no need to change anything, just use the path as is. + // 2. Nothing was found, so let's just return the original path. + return None; + } + } + } + None +} + fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { - let hir::Ty { hir_id: _, span, ref kind } = *hir_ty; + let hir::Ty { hir_id, span, ref kind } = *hir_ty; let hir::TyKind::Path(qpath) = kind else { unreachable!() }; match qpath { hir::QPath::Resolved(None, path) => { if let Res::Def(DefKind::TyParam, did) = path.res { - if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() { + if let Some(new_ty) = cx.args.get(&did).and_then(|p| p.as_ty()).cloned() { return new_ty; } if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) { @@ -1496,7 +1634,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type if let Some(expanded) = maybe_expand_private_type_alias(cx, path) { expanded } else { - let path = clean_path(path, cx); + // First we check if it's a private re-export. + let path = if let Some(path) = first_non_private(cx, hir_id, &path) { + path + } else { + clean_path(path, cx) + }; resolve_type(cx, path) } } @@ -1563,7 +1706,7 @@ fn maybe_expand_private_type_alias<'tcx>( cx: &mut DocContext<'tcx>, path: &hir::Path<'tcx>, ) -> Option<Type> { - let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; + let Res::Def(DefKind::TyAlias { .. }, def_id) = path.res else { return None }; // Substitute private type aliases let def_id = def_id.as_local()?; let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) @@ -1576,7 +1719,7 @@ fn maybe_expand_private_type_alias<'tcx>( let hir::ItemKind::TyAlias(ty, generics) = alias else { return None }; let provided_params = &path.segments.last().expect("segments were empty"); - let mut substs = DefIdMap::default(); + let mut args = DefIdMap::default(); let generic_args = provided_params.args(); let mut indices: hir::GenericParamCount = Default::default(); @@ -1600,7 +1743,7 @@ fn maybe_expand_private_type_alias<'tcx>( } else { Lifetime::elided() }; - substs.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned)); + args.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned)); } indices.lifetimes += 1; } @@ -1617,10 +1760,9 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ty) = type_ { - substs.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); + args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); } else if let Some(default) = *default { - substs - .insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx))); + args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx))); } indices.types += 1; } @@ -1637,7 +1779,7 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ct) = const_ { - substs.insert( + args.insert( param.def_id.to_def_id(), SubstParam::Constant(clean_const(ct, cx)), ); @@ -1648,7 +1790,7 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx))) + Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx))) } pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { @@ -1725,11 +1867,11 @@ fn normalize<'tcx>( .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)); match normalized { Ok(normalized_value) => { - debug!("normalized {:?} to {:?}", ty, normalized_value); + debug!("normalized {ty:?} to {normalized_value:?}"); Some(normalized_value) } Err(err) => { - debug!("failed to normalize {:?}: {:?}", ty, err); + debug!("failed to normalize {ty:?}: {err:?}"); None } } @@ -1922,7 +2064,7 @@ pub(crate) fn clean_middle_ty<'tcx>( abi: sig.abi(), })) } - ty::Adt(def, substs) => { + ty::Adt(def, args) => { let did = def.did(); let kind = match def.adt_kind() { AdtKind::Struct => ItemType::Struct, @@ -1930,7 +2072,7 @@ pub(crate) fn clean_middle_ty<'tcx>( AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(substs)); + let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } ty::Foreign(did) => { @@ -1940,7 +2082,7 @@ pub(crate) fn clean_middle_ty<'tcx>( did, false, ThinVec::new(), - ty::Binder::dummy(InternalSubsts::empty()), + ty::Binder::dummy(ty::GenericArgs::empty()), ); Type::Path { path } } @@ -1953,10 +2095,10 @@ pub(crate) fn clean_middle_ty<'tcx>( .principal_def_id() .or_else(|| dids.next()) .unwrap_or_else(|| panic!("found trait object `{bound_ty:?}` with no traits?")); - let substs = match obj.principal() { - Some(principal) => principal.map_bound(|p| p.substs), - // marker traits have no substs. - _ => ty::Binder::dummy(InternalSubsts::empty()), + let args = match obj.principal() { + Some(principal) => principal.map_bound(|p| p.args), + // marker traits have no args. + _ => ty::Binder::dummy(ty::GenericArgs::empty()), }; inline::record_extern_fqn(cx, did, ItemType::Trait); @@ -1965,7 +2107,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let mut bounds = dids .map(|did| { - let empty = ty::Binder::dummy(InternalSubsts::empty()); + let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = external_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); PolyTrait { trait_: path, generic_params: Vec::new() } @@ -1979,7 +2121,7 @@ pub(crate) fn clean_middle_ty<'tcx>( pb.map_bound(|pb| { pb // HACK(compiler-errors): Doesn't actually matter what self - // type we put here, because we're only using the GAT's substs. + // type we put here, because we're only using the GAT's args. .with_self_ty(cx.tcx, cx.tcx.types.self_param) .projection_ty }), @@ -2005,7 +2147,7 @@ pub(crate) fn clean_middle_ty<'tcx>( .collect(); let late_bound_regions = late_bound_regions.into_iter().collect(); - let path = external_path(cx, did, false, bindings, substs); + let path = external_path(cx, did, false, bindings, args); bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions }); DynTrait(bounds, lifetime) @@ -2026,9 +2168,9 @@ pub(crate) fn clean_middle_ty<'tcx>( assoc: PathSegment { name: cx.tcx.associated_item(alias_ty.skip_binder().def_id).name, args: GenericArgs::AngleBracketed { - args: substs_to_args( + args: ty_args_to_args( cx, - alias_ty.map_bound(|ty| ty.substs.as_slice()), + alias_ty.map_bound(|ty| ty.args.as_slice()), true, None, ) @@ -2051,11 +2193,11 @@ pub(crate) fn clean_middle_ty<'tcx>( data.def_id, false, ThinVec::new(), - bound_ty.rebind(data.substs), + bound_ty.rebind(data.args), ); Type::Path { path } } else { - let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); + let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args); clean_middle_ty(bound_ty.rebind(ty), cx, None, None) } } @@ -2068,11 +2210,10 @@ pub(crate) fn clean_middle_ty<'tcx>( } } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // If it's already in the same alias, don't get an infinite loop. if cx.current_type_aliases.contains_key(&def_id) { - let path = - external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(substs)); + let path = external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } else { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; @@ -2081,7 +2222,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let bounds = cx .tcx .explicit_item_bounds(def_id) - .subst_iter_copied(cx.tcx, substs) + .iter_instantiated_copied(cx.tcx, args) .map(|(bound, _)| bound) .collect::<Vec<_>>(); let ty = clean_middle_opaque_bounds(cx, bounds); @@ -2110,7 +2251,6 @@ fn clean_middle_opaque_bounds<'tcx>( cx: &mut DocContext<'tcx>, bounds: Vec<ty::Clause<'tcx>>, ) -> Type { - let mut regions = vec![]; let mut has_sized = false; let mut bounds = bounds .iter() @@ -2119,10 +2259,7 @@ fn clean_middle_opaque_bounds<'tcx>( let trait_ref = match bound_predicate.skip_binder() { ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref), ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => { - if let Some(r) = clean_middle_region(reg) { - regions.push(GenericBound::Outlives(r)); - } - return None; + return clean_middle_region(reg).map(GenericBound::Outlives); } _ => return None, }; @@ -2158,10 +2295,20 @@ fn clean_middle_opaque_bounds<'tcx>( Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings)) }) .collect::<Vec<_>>(); - bounds.extend(regions); - if !has_sized && !bounds.is_empty() { - bounds.insert(0, GenericBound::maybe_sized(cx)); + + if !has_sized { + bounds.push(GenericBound::maybe_sized(cx)); + } + + // Move trait bounds to the front. + bounds.sort_by_key(|b| !b.is_trait_bound()); + + // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`). + // Since all potential trait bounds are at the front we can just check the first bound. + if bounds.first().map_or(true, |b| !b.is_trait_bound()) { + bounds.insert(0, GenericBound::sized(cx)); } + ImplTrait(bounds) } @@ -2174,7 +2321,7 @@ pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext field.did, field.name, clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(field.did).subst_identity()), + ty::Binder::dummy(cx.tcx.type_of(field.did).instantiate_identity()), cx, Some(field.did), None, @@ -2305,10 +2452,10 @@ fn clean_bare_fn_ty<'tcx>( pub(crate) fn reexport_chain<'tcx>( tcx: TyCtxt<'tcx>, import_def_id: LocalDefId, - target_def_id: LocalDefId, + target_def_id: DefId, ) -> &'tcx [Reexport] { for child in tcx.module_children_local(tcx.local_parent(import_def_id)) { - if child.res.opt_def_id() == Some(target_def_id.to_def_id()) + if child.res.opt_def_id() == Some(target_def_id) && child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id()) { return &child.reexport_chain; @@ -2321,7 +2468,7 @@ pub(crate) fn reexport_chain<'tcx>( fn get_all_import_attributes<'hir>( cx: &mut DocContext<'hir>, import_def_id: LocalDefId, - target_def_id: LocalDefId, + target_def_id: DefId, is_inline: bool, ) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> { let mut attrs = Vec::new(); @@ -2336,7 +2483,7 @@ fn get_all_import_attributes<'hir>( attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect(); first = false; // We don't add attributes of an intermediate re-export if it has `#[doc(hidden)]`. - } else if !cx.tcx.is_doc_hidden(def_id) { + } else if cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id) { add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id)); } } @@ -2344,19 +2491,19 @@ fn get_all_import_attributes<'hir>( } fn filter_tokens_from_list( - args_tokens: TokenStream, + args_tokens: &TokenStream, should_retain: impl Fn(&TokenTree) -> bool, ) -> Vec<TokenTree> { let mut tokens = Vec::with_capacity(args_tokens.len()); let mut skip_next_comma = false; - for token in args_tokens.into_trees() { + for token in args_tokens.trees() { match token { TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => { skip_next_comma = false; } - token if should_retain(&token) => { + token if should_retain(token) => { skip_next_comma = false; - tokens.push(token); + tokens.push(token.clone()); } _ => { skip_next_comma = true; @@ -2414,7 +2561,7 @@ fn add_without_unwanted_attributes<'hir>( match normal.item.args { ast::AttrArgs::Delimited(ref mut args) => { let tokens = - filter_tokens_from_list(args.tokens.clone(), |token| { + filter_tokens_from_list(&args.tokens, |token| { !matches!( token, TokenTree::Token( @@ -2458,8 +2605,9 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Static(ty, mutability, body_id) => { StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) } - ItemKind::Const(ty, body_id) => ConstantItem(Constant { + ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant { type_: clean_ty(ty, cx), + generics: Box::new(clean_generics(generics, cx)), kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { @@ -2538,7 +2686,7 @@ fn clean_maybe_renamed_item<'tcx>( vec![generate_item_with_correct_attrs( cx, kind, - item.owner_id.def_id, + item.owner_id.def_id.to_def_id(), name, import_id, renamed, @@ -2574,8 +2722,8 @@ fn clean_impl<'tcx>( let for_ = clean_ty(impl_.self_ty, cx); let type_alias = for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) { - DefKind::TyAlias => Some(clean_middle_ty( - ty::Binder::dummy(tcx.type_of(def_id).subst_identity()), + DefKind::TyAlias { .. } => Some(clean_middle_ty( + ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()), cx, Some(def_id.to_def_id()), None, @@ -2640,15 +2788,12 @@ fn clean_extern_crate<'tcx>( } } - // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason - vec![Item { - name: Some(name), - attrs: Box::new(Attributes::from_ast(attrs)), - item_id: crate_def_id.into(), - kind: Box::new(ExternCrateItem { src: orig_name }), - cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), - inline_stmt_id: Some(krate_owner_def_id), - }] + vec![Item::from_def_id_and_parts( + krate_owner_def_id, + Some(name), + ExternCrateItem { src: orig_name }, + cx, + )] } fn clean_use_statement<'tcx>( @@ -2662,9 +2807,6 @@ fn clean_use_statement<'tcx>( let mut items = Vec::new(); let hir::UsePath { segments, ref res, span } = *path; for &res in res { - if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res { - continue; - } let path = hir::Path { segments, res, span }; items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names)); } @@ -2679,6 +2821,9 @@ fn clean_use_statement_inner<'tcx>( cx: &mut DocContext<'tcx>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Vec<Item> { + if should_ignore_res(path.res) { + return Vec::new(); + } // We need this comparison because some imports (for std types for example) // are "inserted" as well but directly by the compiler and they should not be // taken into account. @@ -2691,11 +2836,12 @@ fn clean_use_statement_inner<'tcx>( let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline); let pub_underscore = visibility.is_public() && name == kw::Underscore; let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); + let import_def_id = import.owner_id.def_id.to_def_id(); // The parent of the module in which this import resides. This // is the same as `current_mod` if that's already the top // level module. - let parent_mod = cx.tcx.parent_module_from_def_id(current_mod); + let parent_mod = cx.tcx.parent_module_from_def_id(current_mod.to_local_def_id()); // This checks if the import can be seen from a higher level module. // In other words, it checks if the visibility is the equivalent of @@ -2741,9 +2887,14 @@ fn clean_use_statement_inner<'tcx>( let inner = if kind == hir::UseKind::Glob { if !denied { let mut visited = DefIdSet::default(); - if let Some(items) = - inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names) - { + if let Some(items) = inline::try_inline_glob( + cx, + path.res, + current_mod, + &mut visited, + inlined_names, + import, + ) { return items; } } @@ -2759,7 +2910,6 @@ fn clean_use_statement_inner<'tcx>( denied = true; } if !denied { - let import_def_id = import.owner_id.to_def_id(); if let Some(mut items) = inline::try_inline( cx, path.res, @@ -2779,7 +2929,7 @@ fn clean_use_statement_inner<'tcx>( Import::new_simple(name, resolve_use_source(cx, path), true) }; - vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)] + vec![Item::from_def_id_and_parts(import_def_id, None, ImportItem(inner), cx)] } fn clean_maybe_renamed_foreign_item<'tcx>( diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index ef38ca3c1..66d10f236 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -76,17 +76,13 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String }; // Reparse a single token tree. - let mut reparsed_trees = match parser.parse_all_token_trees() { - Ok(reparsed_trees) => reparsed_trees, - Err(diagnostic) => { - diagnostic.cancel(); - return None; - } - }; - if reparsed_trees.len() != 1 { + if parser.token == token::Eof { + return None; + } + let reparsed_tree = parser.parse_token_tree(); + if parser.token != token::Eof { return None; } - let reparsed_tree = reparsed_trees.pop().unwrap(); // Compare against the original tree. if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 65b1b72ad..7b8f20326 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -47,7 +47,9 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP // Look for equality predicates on associated types that can be merged into // general bound predicates. equalities.retain(|(lhs, rhs, bound_params)| { - let Some((ty, trait_did, name)) = lhs.projection() else { return true; }; + let Some((ty, trait_did, name)) = lhs.projection() else { + return true; + }; let Some((bounds, _)) = tybounds.get_mut(ty) else { return true }; merge_bounds(cx, bounds, bound_params.clone(), trait_did, name, rhs) }); @@ -136,3 +138,38 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) }) .any(|did| trait_is_same_or_supertrait(cx, did, trait_)) } + +/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to +/// the respective parameter. +/// +/// There is no guarantee that this is what the user actually wrote but we have no way of knowing. +// FIXME(fmease): It'd make a lot of sense to just incorporate this logic into `clean_ty_generics` +// making every of its users benefit from it. +pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) { + use clean::types::*; + + let mut where_predicates = ThinVec::new(); + for mut pred in generics.where_predicates.drain(..) { + if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.append(bounds); + } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Lifetime { outlives: param_bounds }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.extend(bounds.drain(..).map(|bound| match bound { + GenericBound::Outlives(lifetime) => lifetime, + _ => unreachable!(), + })); + } else { + where_predicates.push(pred); + } + } + generics.where_predicates = where_predicates; +} diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 26139d527..49bde1d31 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -78,7 +78,7 @@ impl ItemId { #[track_caller] pub(crate) fn expect_def_id(self) -> DefId { self.as_def_id() - .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self)) + .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId")) } #[inline] @@ -352,7 +352,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { match tcx.def_kind(parent) { DefKind::Struct | DefKind::Union => false, DefKind::Variant => true, - parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), + parent_kind => panic!("unexpected parent kind: {parent_kind:?}"), } } @@ -436,7 +436,7 @@ impl Item { attrs: Box<Attributes>, cfg: Option<Arc<Cfg>>, ) -> Item { - trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg); + trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}"); Item { item_id: def_id.into(), @@ -451,11 +451,7 @@ impl Item { pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> { use crate::html::format::{href, link_tooltip}; - let Some(links) = cx.cache() - .intra_doc_links - .get(&self.item_id) else { - return vec![] - }; + let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] }; links .iter() .filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| { @@ -484,11 +480,9 @@ 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> { - let Some(links) = cache - .intra_doc_links - .get(&self.item_id) else { - return vec![]; - }; + let Some(links) = cache.intra_doc_links.get(&self.item_id) else { + return vec![]; + }; links .iter() .map(|ItemLink { link: s, link_text, .. }| RenderedLink { @@ -830,9 +824,9 @@ pub(crate) enum ItemKind { ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), /// A required associated constant in a trait declaration. - TyAssocConstItem(Type), + TyAssocConstItem(Box<Generics>, Type), /// An associated constant in a trait impl or a provided one in a trait declaration. - AssocConstItem(Type, ConstantKind), + AssocConstItem(Box<Generics>, Type, ConstantKind), /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. @@ -877,8 +871,8 @@ impl ItemKind { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | TyAssocConstItem(_) - | AssocConstItem(_, _) + | TyAssocConstItem(..) + | AssocConstItem(..) | TyAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) @@ -1225,15 +1219,24 @@ pub(crate) enum GenericBound { } impl GenericBound { + pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound { + Self::sized_with(cx, hir::TraitBoundModifier::None) + } + pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { + Self::sized_with(cx, hir::TraitBoundModifier::Maybe) + } + + fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); - let empty = ty::Binder::dummy(ty::InternalSubsts::empty()); + let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = external_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - GenericBound::TraitBound( - PolyTrait { trait_: path, generic_params: Vec::new() }, - hir::TraitBoundModifier::Maybe, - ) + GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) + } + + pub(crate) fn is_trait_bound(&self) -> bool { + matches!(self, Self::TraitBound(..)) } pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { @@ -1275,7 +1278,7 @@ impl Lifetime { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> }, RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, @@ -1345,7 +1348,7 @@ impl GenericParamDef { } // maybe use a Generic enum and use Vec<Generic>? -#[derive(Clone, Debug, Default)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] pub(crate) struct Generics { pub(crate) params: ThinVec<GenericParamDef>, pub(crate) where_predicates: ThinVec<WherePredicate>, @@ -1782,7 +1785,6 @@ impl PrimitiveType { } pub(crate) fn simplified_types() -> &'static SimplifiedTypes { - use ty::fast_reject::SimplifiedType::*; use ty::{FloatTy, IntTy, UintTy}; use PrimitiveType::*; static CELL: OnceCell<SimplifiedTypes> = OnceCell::new(); @@ -1790,38 +1792,38 @@ impl PrimitiveType { let single = |x| iter::once(x).collect(); CELL.get_or_init(move || { map! { - Isize => single(IntSimplifiedType(IntTy::Isize)), - I8 => single(IntSimplifiedType(IntTy::I8)), - I16 => single(IntSimplifiedType(IntTy::I16)), - I32 => single(IntSimplifiedType(IntTy::I32)), - I64 => single(IntSimplifiedType(IntTy::I64)), - I128 => single(IntSimplifiedType(IntTy::I128)), - Usize => single(UintSimplifiedType(UintTy::Usize)), - U8 => single(UintSimplifiedType(UintTy::U8)), - U16 => single(UintSimplifiedType(UintTy::U16)), - U32 => single(UintSimplifiedType(UintTy::U32)), - U64 => single(UintSimplifiedType(UintTy::U64)), - U128 => single(UintSimplifiedType(UintTy::U128)), - F32 => single(FloatSimplifiedType(FloatTy::F32)), - F64 => single(FloatSimplifiedType(FloatTy::F64)), - Str => single(StrSimplifiedType), - Bool => single(BoolSimplifiedType), - Char => single(CharSimplifiedType), - Array => single(ArraySimplifiedType), - Slice => single(SliceSimplifiedType), + Isize => single(SimplifiedType::Int(IntTy::Isize)), + I8 => single(SimplifiedType::Int(IntTy::I8)), + I16 => single(SimplifiedType::Int(IntTy::I16)), + I32 => single(SimplifiedType::Int(IntTy::I32)), + I64 => single(SimplifiedType::Int(IntTy::I64)), + I128 => single(SimplifiedType::Int(IntTy::I128)), + Usize => single(SimplifiedType::Uint(UintTy::Usize)), + U8 => single(SimplifiedType::Uint(UintTy::U8)), + U16 => single(SimplifiedType::Uint(UintTy::U16)), + U32 => single(SimplifiedType::Uint(UintTy::U32)), + U64 => single(SimplifiedType::Uint(UintTy::U64)), + U128 => single(SimplifiedType::Uint(UintTy::U128)), + F32 => single(SimplifiedType::Float(FloatTy::F32)), + F64 => single(SimplifiedType::Float(FloatTy::F64)), + Str => single(SimplifiedType::Str), + Bool => single(SimplifiedType::Bool), + Char => single(SimplifiedType::Char), + Array => single(SimplifiedType::Array), + Slice => single(SimplifiedType::Slice), // FIXME: If we ever add an inherent impl for tuples // with different lengths, they won't show in rustdoc. // // Either manually update this arrayvec at this point // or start with a more complex refactoring. - Tuple => [TupleSimplifiedType(1), TupleSimplifiedType(2), TupleSimplifiedType(3)].into(), - Unit => single(TupleSimplifiedType(0)), - RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into_iter().collect(), - Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(), + Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(), + Unit => single(SimplifiedType::Tuple(0)), + RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(), + Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(), // FIXME: This will be wrong if we ever add inherent impls // for function pointers. - Fn => single(FunctionSimplifiedType(1)), - Never => single(NeverSimplifiedType), + Fn => single(SimplifiedType::Function(1)), + Never => single(SimplifiedType::Never), } }) } @@ -2210,6 +2212,17 @@ pub(crate) enum GenericArgs { Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> }, } +impl GenericArgs { + pub(crate) fn is_empty(&self) -> bool { + match self { + GenericArgs::AngleBracketed { args, bindings } => { + args.is_empty() && bindings.is_empty() + } + GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(), + } + } +} + #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct PathSegment { pub(crate) name: Symbol, @@ -2253,6 +2266,7 @@ pub(crate) struct Static { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct Constant { pub(crate) type_: Type, + pub(crate) generics: Box<Generics>, pub(crate) kind: ConstantKind, } @@ -2502,7 +2516,8 @@ mod size_asserts { static_assert_size!(GenericParamDef, 56); static_assert_size!(Generics, 16); static_assert_size!(Item, 56); - static_assert_size!(ItemKind, 64); + // FIXME(generic_const_items): Further reduce the size. + static_assert_size!(ItemKind, 72); static_assert_size!(PathSegment, 40); static_assert_size!(Type, 32); // tidy-alphabetical-end diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 394954208..4907a5527 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -73,7 +73,7 @@ fn should_not_trim() { fn is_same_generic() { use crate::clean::types::{PrimitiveType, Type}; use crate::formats::cache::Cache; - let cache = Cache::new(false); + let cache = Cache::new(false, false); let generic = Type::Generic(rustc_span::symbol::sym::Any); let unit = Type::Primitive(PrimitiveType::Unit); assert!(!generic.is_doc_subtype_of(&unit, &cache)); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b786ecbe3..a86bbcc76 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -13,11 +13,10 @@ use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_middle::mir; use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; @@ -39,11 +38,15 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { for it in &module.items { // `compiler_builtins` should be masked too, but we can't apply // `#[doc(masked)]` to the injected `extern crate` because it's unstable. - if it.is_extern_crate() - && (it.attrs.has_doc_flag(sym::masked) - || cx.tcx.is_compiler_builtins(it.item_id.krate())) - { + if cx.tcx.is_compiler_builtins(it.item_id.krate()) { cx.cache.masked_crates.insert(it.item_id.krate()); + } else if it.is_extern_crate() + && it.attrs.has_doc_flag(sym::masked) + && let Some(def_id) = it.item_id.as_def_id() + && let Some(local_def_id) = def_id.as_local() + && let Some(cnum) = cx.tcx.extern_mod_stmt_cnum(local_def_id) + { + cx.cache.masked_crates.insert(cnum); } } } @@ -71,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { Crate { module, external_traits: cx.external_traits.clone() } } -pub(crate) fn substs_to_args<'tcx>( +pub(crate) fn ty_args_to_args<'tcx>( cx: &mut DocContext<'tcx>, args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, has_self: bool, @@ -114,12 +117,12 @@ fn external_generic_args<'tcx>( did: DefId, has_self: bool, bindings: ThinVec<TypeBinding>, - substs: ty::Binder<'tcx, SubstsRef<'tcx>>, + ty_args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> GenericArgs { - let args = substs_to_args(cx, substs.map_bound(|substs| &substs[..]), has_self, Some(did)); + let args = ty_args_to_args(cx, ty_args.map_bound(|args| &args[..]), has_self, Some(did)); if cx.tcx.fn_trait_kind_from_def_id(did).is_some() { - let ty = substs + let ty = ty_args .iter() .nth(if has_self { 1 } else { 0 }) .unwrap() @@ -147,7 +150,7 @@ pub(super) fn external_path<'tcx>( did: DefId, has_self: bool, bindings: ThinVec<TypeBinding>, - substs: ty::Binder<'tcx, SubstsRef<'tcx>>, + args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> Path { let def_kind = cx.tcx.def_kind(did); let name = cx.tcx.item_name(did); @@ -155,7 +158,7 @@ pub(super) fn external_path<'tcx>( res: Res::Def(def_kind, did), segments: thin_vec![PathSegment { name, - args: external_generic_args(cx, did, has_self, bindings, substs), + args: external_generic_args(cx, did, has_self, bindings, args), }], } } @@ -217,7 +220,7 @@ pub(crate) fn build_deref_target_impls( pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { use rustc_hir::*; - debug!("trying to get a name from pattern: {:?}", p); + debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match p.kind { PatKind::Wild | PatKind::Struct(..) => return kw::Underscore, @@ -250,7 +253,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { match n.kind() { - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs: _ }) => { + ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => { let s = if let Some(def) = def.as_local() { print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def)) } else { @@ -275,7 +278,7 @@ pub(crate) fn print_evaluated_const( underscores_and_type: bool, ) -> Option<String> { tcx.const_eval_poly(def_id).ok().and_then(|val| { - let ty = tcx.type_of(def_id).subst_identity(); + let ty = tcx.type_of(def_id).instantiate_identity(); match (val, ty.kind()) { (_, &ty::Ref(..)) => None, (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, @@ -460,7 +463,7 @@ pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { /// Given a type Path, resolve it to a Type using the TyCtxt pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { - debug!("resolve_type({:?})", path); + debug!("resolve_type({path:?})"); match path.res { Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), @@ -479,12 +482,6 @@ pub(crate) fn get_auto_trait_and_blanket_impls( cx: &mut DocContext<'_>, item_def_id: DefId, ) -> impl Iterator<Item = Item> { - // FIXME: To be removed once `parallel_compiler` bugs are fixed! - // More information in <https://github.com/rust-lang/rust/pull/106930>. - if cfg!(parallel_compiler) { - return vec![].into_iter().chain(vec![].into_iter()); - } - let auto_impls = cx .sess() .prof @@ -505,16 +502,30 @@ pub(crate) fn get_auto_trait_and_blanket_impls( /// [`href()`]: crate::html::format::href pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { use DefKind::*; - debug!("register_res({:?})", res); + debug!("register_res({res:?})"); let (kind, did) = match res { Res::Def( - kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct - | Union | Mod | ForeignTy | Const | Static(_) | Macro(..) | TraitAlias), + kind @ (AssocTy + | AssocFn + | AssocConst + | Variant + | Fn + | TyAlias { .. } + | Enum + | Trait + | Struct + | Union + | Mod + | ForeignTy + | Const + | Static(_) + | Macro(..) + | TraitAlias), did, ) => (kind.into(), did), - _ => panic!("register_res: unexpected {:?}", res), + _ => panic!("register_res: unexpected {res:?}"), }; if did.is_local() { return did; @@ -592,8 +603,12 @@ pub(super) fn render_macro_arms<'a>( ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim) - .unwrap(); + writeln!( + out, + " {matcher} => {{ ... }}{arm_delim}", + matcher = render_macro_matcher(tcx, matcher), + ) + .unwrap(); } out } @@ -609,22 +624,54 @@ pub(super) fn display_macro_source( let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) + format!("macro_rules! {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ";")) } else { if matchers.len() <= 1 { format!( - "{}macro {}{} {{\n ...\n}}", - visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - name, - matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(), + "{vis}macro {name}{matchers} {{\n ...\n}}", + vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id), + matchers = matchers + .map(|matcher| render_macro_matcher(cx.tcx, matcher)) + .collect::<String>(), ) } else { format!( - "{}macro {} {{\n{}}}", - visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - name, - render_macro_arms(cx.tcx, matchers, ","), + "{vis}macro {name} {{\n{arms}}}", + vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id), + arms = render_macro_arms(cx.tcx, matchers, ","), ) } } } + +pub(crate) fn inherits_doc_hidden( + tcx: TyCtxt<'_>, + mut def_id: LocalDefId, + stop_at: Option<LocalDefId>, +) -> bool { + let hir = tcx.hir(); + while let Some(id) = tcx.opt_local_parent(def_id) { + if let Some(stop_at) = stop_at && id == stop_at { + return false; + } + def_id = id; + if tcx.is_doc_hidden(def_id.to_def_id()) { + return true; + } else if let Some(node) = hir.find_by_def_id(def_id) && + matches!( + node, + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }), + ) + { + // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly + // on them, they don't inherit it from the parent context. + return false; + } + } + false +} + +#[inline] +pub(crate) fn should_ignore_res(res: Res) -> bool { + matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..)) +} |