summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/clean
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r--src/librustdoc/clean/inline.rs23
-rw-r--r--src/librustdoc/clean/mod.rs211
-rw-r--r--src/librustdoc/clean/types.rs121
-rw-r--r--src/librustdoc/clean/utils.rs116
4 files changed, 265 insertions, 206 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cac211307..fcbcfbf5c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol};
use crate::clean::{
self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
- clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type,
+ clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes,
+ AttributesExt, ImplKind, ItemId, Type,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
@@ -79,10 +80,10 @@ 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) => {
- record_extern_fqn(cx, did, ItemType::Typedef);
+ Res::Def(DefKind::TyAlias, did) => {
+ record_extern_fqn(cx, did, ItemType::TypeAlias);
build_impls(cx, did, attrs_without_docs, &mut ret);
- clean::TypedefItem(build_type_alias(cx, did))
+ clean::TypeAliasItem(build_type_alias(cx, did))
}
Res::Def(DefKind::Enum, did) => {
record_extern_fqn(cx, did, ItemType::Enum);
@@ -287,18 +288,16 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
clean::Union { generics, fields }
}
-fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> {
+fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::TypeAlias> {
let predicates = cx.tcx.explicit_predicates_of(did);
- let type_ = clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
- cx,
- Some(did),
- None,
- );
+ let ty = cx.tcx.type_of(did).instantiate_identity();
+ let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None);
+ let inner_type = clean_ty_alias_inner_type(ty, cx);
- Box::new(clean::Typedef {
+ Box::new(clean::TypeAlias {
type_,
generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
+ inner_type,
item_type: None,
})
}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c9a05460b..0caa92e44 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -24,6 +24,7 @@ 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::GenericArgsRef;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
@@ -541,7 +542,7 @@ fn clean_generic_param_def<'tcx>(
},
)
}
- ty::GenericParamDefKind::Const { has_default } => (
+ ty::GenericParamDefKind::Const { has_default, is_host_effect } => (
def.name,
GenericParamDefKind::Const {
ty: Box::new(clean_middle_ty(
@@ -561,6 +562,7 @@ fn clean_generic_param_def<'tcx>(
)),
false => None,
},
+ is_host_effect,
},
),
};
@@ -617,6 +619,7 @@ fn clean_generic_param<'tcx>(
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())),
+ is_host_effect: cx.tcx.has_attr(param.def_id, sym::rustc_host),
},
),
};
@@ -792,6 +795,7 @@ fn clean_ty_generics<'tcx>(
}
Some(clean_generic_param_def(param, cx))
}
+ ty::GenericParamDefKind::Const { is_host_effect: true, .. } => None,
ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
})
.collect::<ThinVec<GenericParamDef>>();
@@ -955,6 +959,43 @@ fn clean_ty_generics<'tcx>(
}
}
+fn clean_ty_alias_inner_type<'tcx>(
+ ty: Ty<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<TypeAliasInnerType> {
+ let ty::Adt(adt_def, args) = ty.kind() else {
+ return None;
+ };
+
+ Some(if adt_def.is_enum() {
+ let variants: rustc_index::IndexVec<_, _> = adt_def
+ .variants()
+ .iter()
+ .map(|variant| clean_variant_def_with_args(variant, args, cx))
+ .collect();
+
+ TypeAliasInnerType::Enum {
+ variants,
+ is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(),
+ }
+ } else {
+ let variant = adt_def
+ .variants()
+ .iter()
+ .next()
+ .unwrap_or_else(|| bug!("a struct or union should always have one variant def"));
+
+ let fields: Vec<_> =
+ clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect();
+
+ if adt_def.is_struct() {
+ TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields }
+ } else {
+ TypeAliasInnerType::Union { fields }
+ }
+ })
+}
+
fn clean_proc_macro<'tcx>(
item: &hir::Item<'tcx>,
name: &mut Symbol,
@@ -1069,10 +1110,7 @@ fn clean_function<'tcx>(
clean_args_from_types_and_names(cx, sig.decl.inputs, names)
}
};
- let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
- if sig.header.is_async() {
- decl.output = decl.sugared_async_return_type();
- }
+ let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args);
(generics, decl)
});
Box::new(Function { decl, generics })
@@ -1123,12 +1161,16 @@ fn clean_args_from_types_and_body_id<'tcx>(
fn clean_fn_decl_with_args<'tcx>(
cx: &mut DocContext<'tcx>,
decl: &hir::FnDecl<'tcx>,
+ header: Option<&hir::FnHeader>,
args: Arguments,
) -> FnDecl {
- let output = match decl.output {
+ let mut output = match decl.output {
hir::FnRetTy::Return(typ) => clean_ty(typ, cx),
hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()),
};
+ if let Some(header) = header && header.is_async() {
+ output = output.sugared_async_return_type();
+ }
FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
}
@@ -1141,7 +1183,17 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
// We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
// but shouldn't change any code meaning.
- let output = clean_middle_ty(sig.output(), cx, None, None);
+ let mut output = clean_middle_ty(sig.output(), cx, None, None);
+
+ // If the return type isn't an `impl Trait`, we can safely assume that this
+ // function isn't async without needing to execute the query `asyncness` at
+ // all which gives us a noticeable performance boost.
+ if let Some(did) = did
+ && let Type::ImplTrait(_) = output
+ && cx.tcx.asyncness(did).is_async()
+ {
+ output = output.sugared_async_return_type();
+ }
FnDecl {
output,
@@ -1219,9 +1271,10 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
None,
);
AssocTypeItem(
- Box::new(Typedef {
+ Box::new(TypeAlias {
type_: clean_ty(default, cx),
generics,
+ inner_type: None,
item_type: Some(item_type),
}),
bounds,
@@ -1264,7 +1317,12 @@ pub(crate) fn clean_impl_item<'tcx>(
None,
);
AssocTypeItem(
- Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
+ Box::new(TypeAlias {
+ type_,
+ generics,
+ inner_type: None,
+ item_type: Some(item_type),
+ }),
Vec::new(),
)
}
@@ -1461,7 +1519,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
if tcx.defaultness(assoc_item.def_id).has_value() {
AssocTypeItem(
- Box::new(Typedef {
+ Box::new(TypeAlias {
type_: clean_middle_ty(
ty::Binder::dummy(
tcx.type_of(assoc_item.def_id).instantiate_identity(),
@@ -1471,6 +1529,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
None,
),
generics,
+ inner_type: None,
item_type: None,
}),
bounds,
@@ -1480,7 +1539,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
}
} else {
AssocTypeItem(
- Box::new(Typedef {
+ Box::new(TypeAlias {
type_: clean_middle_ty(
ty::Binder::dummy(
tcx.type_of(assoc_item.def_id).instantiate_identity(),
@@ -1490,6 +1549,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
None,
),
generics,
+ inner_type: None,
item_type: None,
}),
// Associated types inside trait or inherent impls are not allowed to have
@@ -1706,7 +1766,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())
@@ -1817,7 +1877,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
// does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
let param_env = cx.tcx.param_env(anon_const.def_id);
- print_const(cx, ct.eval(cx.tcx, param_env))
+ print_const(cx, ct.normalize(cx.tcx, param_env))
}
};
@@ -1975,7 +2035,7 @@ impl<'tcx> ContainerTy<'tcx> {
let (DefKind::Struct
| DefKind::Union
| DefKind::Enum
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::Trait) = tcx.def_kind(container)
else {
return ObjectLifetimeDefault::Empty;
@@ -2036,7 +2096,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
ty::Array(ty, mut n) => {
- n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
+ n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
}
@@ -2241,7 +2301,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Bound(..) => panic!("Bound"),
ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
- ty::GeneratorWitnessMIR(..) => panic!("GeneratorWitnessMIR"),
ty::Infer(..) => panic!("Infer"),
ty::Error(_) => rustc_errors::FatalError.raise(),
}
@@ -2363,6 +2422,83 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
)
}
+pub(crate) fn clean_variant_def_with_args<'tcx>(
+ variant: &ty::VariantDef,
+ args: &GenericArgsRef<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Item {
+ let discriminant = match variant.discr {
+ ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+ ty::VariantDiscr::Relative(_) => None,
+ };
+
+ use rustc_middle::traits::ObligationCause;
+ use rustc_trait_selection::infer::TyCtxtInferExt;
+ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+
+ let infcx = cx.tcx.infer_ctxt().build();
+ let kind = match variant.ctor_kind() {
+ Some(CtorKind::Const) => VariantKind::CLike,
+ Some(CtorKind::Fn) => VariantKind::Tuple(
+ variant
+ .fields
+ .iter()
+ .map(|field| {
+ let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args);
+
+ // normalize the type to only show concrete types
+ // note: we do not use try_normalize_erasing_regions since we
+ // do care about showing the regions
+ let ty = infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .query_normalize(ty)
+ .map(|normalized| normalized.value)
+ .unwrap_or(ty);
+
+ clean_field_with_def_id(
+ field.did,
+ field.name,
+ clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
+ cx,
+ )
+ })
+ .collect(),
+ ),
+ None => VariantKind::Struct(VariantStruct {
+ fields: variant
+ .fields
+ .iter()
+ .map(|field| {
+ let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args);
+
+ // normalize the type to only show concrete types
+ // note: we do not use try_normalize_erasing_regions since we
+ // do care about showing the regions
+ let ty = infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .query_normalize(ty)
+ .map(|normalized| normalized.value)
+ .unwrap_or(ty);
+
+ clean_field_with_def_id(
+ field.did,
+ field.name,
+ clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
+ cx,
+ )
+ })
+ .collect(),
+ }),
+ };
+
+ Item::from_def_id_and_parts(
+ variant.def_id,
+ Some(variant.name),
+ VariantItem(Variant { kind, discriminant }),
+ cx,
+ )
+}
+
fn clean_variant_data<'tcx>(
variant: &hir::VariantData<'tcx>,
disr_expr: &Option<hir::AnonConst>,
@@ -2406,14 +2542,22 @@ fn clean_generic_args<'tcx>(
let args = generic_args
.args
.iter()
- .map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
- GenericArg::Lifetime(clean_lifetime(*lt, cx))
- }
- hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
- hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
- hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
- hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+ .filter_map(|arg| {
+ Some(match arg {
+ hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
+ GenericArg::Lifetime(clean_lifetime(*lt, cx))
+ }
+ hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+ hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+ // FIXME(effects): This will still emit `<true>` for non-const impls of const traits
+ hir::GenericArg::Const(ct)
+ if cx.tcx.has_attr(ct.value.def_id, sym::rustc_host) =>
+ {
+ return None;
+ }
+ hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+ hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+ })
})
.collect::<Vec<_>>()
.into();
@@ -2443,7 +2587,7 @@ fn clean_bare_fn_ty<'tcx>(
.map(|x| clean_generic_param(cx, None, x))
.collect();
let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
- let decl = clean_fn_decl_with_args(cx, bare_fn.decl, args);
+ let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
(generic_params, decl)
});
BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
@@ -2617,7 +2761,7 @@ fn clean_maybe_renamed_item<'tcx>(
ItemKind::TyAlias(hir_ty, generics) => {
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
let rustdoc_ty = clean_ty(hir_ty, cx);
- let ty = clean_middle_ty(
+ let type_ = clean_middle_ty(
ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
cx,
None,
@@ -2630,7 +2774,16 @@ fn clean_maybe_renamed_item<'tcx>(
cx.current_type_aliases.remove(&def_id);
}
}
- TypedefItem(Box::new(Typedef { type_: rustdoc_ty, generics, item_type: Some(ty) }))
+
+ let ty = cx.tcx.type_of(def_id).instantiate_identity();
+ let inner_type = clean_ty_alias_inner_type(ty, cx);
+
+ TypeAliasItem(Box::new(TypeAlias {
+ generics,
+ inner_type,
+ type_: rustdoc_ty,
+ item_type: Some(type_),
+ }))
}
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
@@ -2722,7 +2875,7 @@ 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(
+ DefKind::TyAlias => Some(clean_middle_ty(
ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()),
cx,
Some(def_id.to_def_id()),
@@ -2945,7 +3098,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
// NOTE: generics must be cleaned before args
let generics = clean_generics(generics, cx);
let args = clean_args_from_types_and_names(cx, decl.inputs, names);
- let decl = clean_fn_decl_with_args(cx, decl, args);
+ let decl = clean_fn_decl_with_args(cx, decl, None, args);
(generics, decl)
});
ForeignFunctionItem(Box::new(Function { decl, generics }))
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 49bde1d31..4256e7b51 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -22,20 +22,23 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability};
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
use rustc_index::IndexVec;
+use rustc_metadata::rendered_const;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt, Visibility};
-use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment};
+use rustc_resolve::rustdoc::{
+ add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments, DocFragment,
+};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{self, FileName, Loc};
+use rustc_span::{self, FileName, Loc, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
-use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
+use crate::clean::utils::{is_literal_expr, print_evaluated_const};
use crate::core::DocContext;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
@@ -396,7 +399,7 @@ impl Item {
}
pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
- crate::passes::span_of_attrs(&self.attrs)
+ span_of_fragments(&self.attrs.doc_strings)
.unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner()))
}
@@ -530,8 +533,8 @@ impl Item {
pub(crate) fn is_ty_method(&self) -> bool {
self.type_() == ItemType::TyMethod
}
- pub(crate) fn is_typedef(&self) -> bool {
- self.type_() == ItemType::Typedef
+ pub(crate) fn is_type_alias(&self) -> bool {
+ self.type_() == ItemType::TypeAlias
}
pub(crate) fn is_primitive(&self) -> bool {
self.type_() == ItemType::Primitive
@@ -619,7 +622,7 @@ impl Item {
fn build_fn_header(
def_id: DefId,
tcx: TyCtxt<'_>,
- asyncness: hir::IsAsync,
+ asyncness: ty::Asyncness,
) -> hir::FnHeader {
let sig = tcx.fn_sig(def_id).skip_binder();
let constness =
@@ -628,6 +631,10 @@ impl Item {
} else {
hir::Constness::NotConst
};
+ let asyncness = match asyncness {
+ ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
+ ty::Asyncness::No => hir::IsAsync::NotAsync,
+ };
hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
}
let header = match *self.kind {
@@ -799,7 +806,7 @@ pub(crate) enum ItemKind {
EnumItem(Enum),
FunctionItem(Box<Function>),
ModuleItem(Module),
- TypedefItem(Box<Typedef>),
+ TypeAliasItem(Box<TypeAlias>),
OpaqueTyItem(OpaqueTy),
StaticItem(Static),
ConstantItem(Constant),
@@ -832,7 +839,7 @@ pub(crate) enum ItemKind {
/// The bounds may be non-empty if there is a `where` clause.
TyAssocTypeItem(Generics, Vec<GenericBound>),
/// An associated type in a trait impl or a provided one in a trait declaration.
- AssocTypeItem(Box<Typedef>, Vec<GenericBound>),
+ AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemKind>),
KeywordItem,
@@ -857,7 +864,7 @@ impl ItemKind {
ExternCrateItem { .. }
| ImportItem(_)
| FunctionItem(_)
- | TypedefItem(_)
+ | TypeAliasItem(_)
| OpaqueTyItem(_)
| StaticItem(_)
| ConstantItem(_)
@@ -891,7 +898,7 @@ impl ItemKind {
| ModuleItem(_)
| ExternCrateItem { .. }
| FunctionItem(_)
- | TypedefItem(_)
+ | TypeAliasItem(_)
| OpaqueTyItem(_)
| StaticItem(_)
| ConstantItem(_)
@@ -1308,7 +1315,7 @@ impl WherePredicate {
pub(crate) enum GenericParamDefKind {
Lifetime { outlives: Vec<Lifetime> },
Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
- Const { ty: Box<Type>, default: Option<Box<String>> },
+ Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
}
impl GenericParamDefKind {
@@ -1328,9 +1335,10 @@ impl GenericParamDef {
Self { name, kind: GenericParamDefKind::Lifetime { outlives: Vec::new() } }
}
- pub(crate) fn is_synthetic_type_param(&self) -> bool {
+ pub(crate) fn is_synthetic_param(&self) -> bool {
match self.kind {
- GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
+ GenericParamDefKind::Lifetime { .. } => false,
+ GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect,
GenericParamDefKind::Type { synthetic, .. } => synthetic,
}
}
@@ -1377,28 +1385,6 @@ impl FnDecl {
pub(crate) fn self_type(&self) -> Option<SelfTy> {
self.inputs.values.get(0).and_then(|v| v.to_self())
}
-
- /// Returns the sugared return type for an async function.
- ///
- /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
- /// will return `i32`.
- ///
- /// # Panics
- ///
- /// This function will panic if the return type does not match the expected sugaring for async
- /// functions.
- pub(crate) fn sugared_async_return_type(&self) -> Type {
- if let Type::ImplTrait(v) = &self.output &&
- let [GenericBound::TraitBound(PolyTrait { trait_, .. }, _ )] = &v[..]
- {
- let bindings = trait_.bindings().unwrap();
- let ret_ty = bindings[0].term();
- let ty = ret_ty.ty().expect("Unexpected constant return term");
- ty.clone()
- } else {
- panic!("unexpected desugaring of async function")
- }
- }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -1610,6 +1596,30 @@ impl Type {
}
}
+ /// Returns the sugared return type for an async function.
+ ///
+ /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
+ /// will return `i32`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the return type does not match the expected sugaring for async
+ /// functions.
+ pub(crate) fn sugared_async_return_type(self) -> Type {
+ if let Type::ImplTrait(mut v) = self
+ && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _ )) = v.pop()
+ && let Some(segment) = trait_.segments.pop()
+ && let GenericArgs::AngleBracketed { mut bindings, .. } = segment.args
+ && let Some(binding) = bindings.pop()
+ && let TypeBindingKind::Equality { term } = binding.kind
+ && let Term::Type(ty) = term
+ {
+ ty
+ } else {
+ panic!("unexpected async fn return type")
+ }
+ }
+
/// Checks if this is a `T::Name` path for an associated type.
pub(crate) fn is_assoc_ty(&self) -> bool {
match self {
@@ -1636,10 +1646,6 @@ impl Type {
matches!(self, Type::Generic(_))
}
- pub(crate) fn is_impl_trait(&self) -> bool {
- matches!(self, Type::ImplTrait(_))
- }
-
pub(crate) fn is_unit(&self) -> bool {
matches!(self, Type::Tuple(v) if v.is_empty())
}
@@ -2086,7 +2092,7 @@ impl Discriminant {
/// Will be `None` in the case of cross-crate reexports, and may be
/// simplified
pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
- self.expr.map(|body| print_const_expr(tcx, body))
+ self.expr.map(|body| rendered_const(tcx, body))
}
/// Will always be a machine readable number, without underscores or suffixes.
pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String {
@@ -2186,16 +2192,6 @@ impl Path {
}
})
}
-
- pub(crate) fn bindings(&self) -> Option<&[TypeBinding]> {
- self.segments.last().and_then(|seg| {
- if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
- Some(&**bindings)
- } else {
- None
- }
- })
- }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -2230,9 +2226,19 @@ pub(crate) struct PathSegment {
}
#[derive(Clone, Debug)]
-pub(crate) struct Typedef {
+pub(crate) enum TypeAliasInnerType {
+ Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
+ Union { fields: Vec<Item> },
+ Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct TypeAlias {
pub(crate) type_: Type,
pub(crate) generics: Generics,
+ /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
+ /// to be shown directly on the typedef page.
+ pub(crate) inner_type: Option<TypeAliasInnerType>,
/// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
/// alias instead of the final type. This will always have the final type, regardless of whether
/// `type_` came from HIR or from metadata.
@@ -2326,7 +2332,7 @@ impl ConstantKind {
ConstantKind::TyConst { ref expr } => expr.to_string(),
ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
- print_const_expr(tcx, body)
+ rendered_const(tcx, body)
}
}
}
@@ -2465,15 +2471,6 @@ pub(crate) enum TypeBindingKind {
Constraint { bounds: Vec<GenericBound> },
}
-impl TypeBinding {
- pub(crate) fn term(&self) -> &Term {
- match self.kind {
- TypeBindingKind::Equality { ref term } => term,
- _ => panic!("expected equality type binding for parenthesized generic args"),
- }
- }
-}
-
/// The type, lifetime, or constant that a private type alias's parameter should be
/// replaced with when expanding a use of that type alias.
///
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a86bbcc76..61e653423 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -14,8 +14,8 @@ use rustc_ast::tokenstream::TokenTree;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_metadata::rendered_const;
use rustc_middle::mir;
-use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
@@ -104,6 +104,10 @@ pub(crate) fn ty_args_to_args<'tcx>(
arg: index,
}),
))),
+ // FIXME(effects): this relies on the host effect being called `host`, which users could also name
+ // their const generics.
+ // FIXME(effects): this causes `host = true` and `host = false` generics to also be emitted.
+ GenericArgKind::Const(ct) if let ty::ConstKind::Param(p) = ct.kind() && p.name == sym::host => None,
GenericArgKind::Const(ct) => {
Some(GenericArg::Const(Box::new(clean_middle_const(kind.rebind(ct), cx))))
}
@@ -153,7 +157,7 @@ pub(super) fn external_path<'tcx>(
args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
) -> Path {
let def_kind = cx.tcx.def_kind(did);
- let name = cx.tcx.item_name(did);
+ let name = cx.tcx.opt_item_name(did).unwrap_or(kw::Empty);
Path {
res: Res::Def(def_kind, did),
segments: thin_vec![PathSegment {
@@ -255,7 +259,7 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
match n.kind() {
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))
+ rendered_const(cx.tcx, cx.tcx.hir().body_owned_by(def))
} else {
inline::print_inlined_const(cx.tcx, def)
};
@@ -281,9 +285,9 @@ pub(crate) fn print_evaluated_const(
let ty = tcx.type_of(def_id).instantiate_identity();
match (val, ty.kind()) {
(_, &ty::Ref(..)) => None,
- (ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
- (ConstValue::Scalar(_), _) => {
- let const_ = mir::ConstantKind::from_value(val, ty);
+ (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
+ (mir::ConstValue::Scalar(_), _) => {
+ let const_ = mir::Const::from_value(val, ty);
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
}
_ => None,
@@ -319,20 +323,20 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
fn print_const_with_custom_print_scalar<'tcx>(
tcx: TyCtxt<'tcx>,
- ct: mir::ConstantKind<'tcx>,
+ ct: mir::Const<'tcx>,
underscores_and_type: bool,
) -> String {
// Use a slightly different format for integer types which always shows the actual value.
// For all other types, fallback to the original `pretty_print_const`.
match (ct, ct.ty().kind()) {
- (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
+ (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
if underscores_and_type {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
} else {
int.to_string()
}
}
- (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
+ (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
let ty = ct.ty();
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
@@ -367,100 +371,6 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
false
}
-/// Build a textual representation of an unevaluated constant expression.
-///
-/// If the const expression is too complex, an underscore `_` is returned.
-/// For const arguments, it's `{ _ }` to be precise.
-/// This means that the output is not necessarily valid Rust code.
-///
-/// Currently, only
-///
-/// * literals (optionally with a leading `-`)
-/// * unit `()`
-/// * blocks (`{ … }`) around simple expressions and
-/// * paths without arguments
-///
-/// are considered simple enough. Simple blocks are included since they are
-/// necessary to disambiguate unit from the unit type.
-/// This list might get extended in the future.
-///
-/// Without this censoring, in a lot of cases the output would get too large
-/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs.
-/// Further, private and `doc(hidden)` fields of structs would get leaked
-/// since HIR datatypes like the `body` parameter do not contain enough
-/// semantic information for this function to be able to hide them –
-/// at least not without significant performance overhead.
-///
-/// Whenever possible, prefer to evaluate the constant first and try to
-/// use a different method for pretty-printing. Ideally this function
-/// should only ever be used as a fallback.
-pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
- let hir = tcx.hir();
- let value = &hir.body(body).value;
-
- #[derive(PartialEq, Eq)]
- enum Classification {
- Literal,
- Simple,
- Complex,
- }
-
- use Classification::*;
-
- fn classify(expr: &hir::Expr<'_>) -> Classification {
- match &expr.kind {
- hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
- if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex }
- }
- hir::ExprKind::Lit(_) => Literal,
- hir::ExprKind::Tup([]) => Simple,
- hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => {
- if classify(expr) == Complex { Complex } else { Simple }
- }
- // Paths with a self-type or arguments are too “complex” following our measure since
- // they may leak private fields of structs (with feature `adt_const_params`).
- // Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`.
- // Paths without arguments are definitely harmless though.
- hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => {
- if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex }
- }
- // FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty
- // contains const arguments. Is there a *concise* way to check for this?
- hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple,
- // FIXME: Can they contain const arguments and thus leak private struct fields?
- hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple,
- _ => Complex,
- }
- }
-
- let classification = classify(value);
-
- if classification == Literal
- && !value.span.from_expansion()
- && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) {
- // For literals, we avoid invoking the pretty-printer and use the source snippet instead to
- // preserve certain stylistic choices the user likely made for the sake legibility like
- //
- // * hexadecimal notation
- // * underscores
- // * character escapes
- //
- // FIXME: This passes through `-/*spacer*/0` verbatim.
- snippet
- } else if classification == Simple {
- // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and
- // other formatting artifacts.
- rustc_hir_pretty::id_to_string(&hir, body.hir_id)
- } else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst {
- // FIXME: Omit the curly braces if the enclosing expression is an array literal
- // with a repeated element (an `ExprKind::Repeat`) as in such case it
- // would not actually need any disambiguation.
- "{ _ }".to_owned()
- } else {
- "_".to_owned()
- }
-}
-
/// 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:?})");