Rollup merge of #128471 - camelid:rustdoc-self, r=notriddle
rustdoc: Fix handling of `Self` type in search index and refactor its representation ### Summary - Add enum variant `clean::Type::SelfTy` and use it instead of `clean::Type::Generic(kw::SelfUpper)`. - Stop treating `Self` as a generic in the search index. - Remove struct formerly known as `clean::SelfTy` (constructed as representation of function receiver type). We're better off without it. ### Before ![image](https://github.com/user-attachments/assets/d257bdd8-3a62-4c71-84a5-9c950f2e4f00) ### After ![image](https://github.com/user-attachments/assets/8f6d3f22-92c1-41e3-9ab8-a881b66816c0) r? ```@notriddle``` cc https://github.com/rust-lang/rust/pull/127589#issuecomment-2259715841
This commit is contained in:
commit
4adefa4334
@ -12,7 +12,7 @@
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
@ -792,11 +792,7 @@ fn build_macro(
|
||||
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
|
||||
for pred in &mut g.where_predicates {
|
||||
match *pred {
|
||||
clean::WherePredicate::BoundPredicate {
|
||||
ty: clean::Generic(ref s),
|
||||
ref mut bounds,
|
||||
..
|
||||
} if *s == kw::SelfUpper => {
|
||||
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
|
||||
bounds.retain(|bound| match bound {
|
||||
clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
|
||||
trait_.def_id() != trait_did
|
||||
@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
|
||||
clean::WherePredicate::BoundPredicate {
|
||||
ty:
|
||||
clean::QPath(box clean::QPathData {
|
||||
self_type: clean::Generic(ref s),
|
||||
self_type: clean::Generic(_),
|
||||
trait_: Some(trait_),
|
||||
..
|
||||
}),
|
||||
bounds,
|
||||
..
|
||||
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
|
||||
} => !bounds.is_empty() && trait_.def_id() != trait_did,
|
||||
_ => true,
|
||||
});
|
||||
g
|
||||
@ -832,9 +828,7 @@ fn separate_supertrait_bounds(
|
||||
) -> (clean::Generics, Vec<clean::GenericBound>) {
|
||||
let mut ty_bounds = Vec::new();
|
||||
g.where_predicates.retain(|pred| match *pred {
|
||||
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
|
||||
if *s == kw::SelfUpper =>
|
||||
{
|
||||
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
|
||||
ty_bounds.extend(bounds.iter().cloned());
|
||||
false
|
||||
}
|
||||
|
@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
||||
let self_arg_ty =
|
||||
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
|
||||
if self_arg_ty == self_ty {
|
||||
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
|
||||
item.decl.inputs.values[0].type_ = SelfTy;
|
||||
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
|
||||
if ty == self_ty {
|
||||
match item.decl.inputs.values[0].type_ {
|
||||
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
|
||||
BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -1439,9 +1439,8 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
if trait_.def_id() != assoc_item.container_id(tcx) {
|
||||
return true;
|
||||
}
|
||||
match *self_type {
|
||||
Generic(ref s) if *s == kw::SelfUpper => {}
|
||||
_ => return true,
|
||||
if *self_type != SelfTy {
|
||||
return true;
|
||||
}
|
||||
match &assoc.args {
|
||||
GenericArgs::AngleBracketed { args, constraints } => {
|
||||
@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
||||
ty::Param(ref p) => {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||
ImplTrait(bounds)
|
||||
} else if p.name == kw::SelfUpper {
|
||||
SelfTy
|
||||
} else {
|
||||
Generic(p.name)
|
||||
}
|
||||
|
@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
|
||||
// should be handled when cleaning associated types.
|
||||
generics.where_predicates.retain(|pred| {
|
||||
if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
|
||||
&& *param != rustc_span::symbol::kw::SelfUpper
|
||||
&& bounds.iter().any(|b| b.is_sized_bound(cx))
|
||||
{
|
||||
sized_params.insert(*param);
|
||||
|
@ -34,10 +34,9 @@
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
pub(crate) use self::ItemKind::*;
|
||||
pub(crate) use self::SelfTy::*;
|
||||
pub(crate) use self::Type::{
|
||||
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
|
||||
RawPointer, Slice, Tuple,
|
||||
RawPointer, SelfTy, Slice, Tuple,
|
||||
};
|
||||
use crate::clean::cfg::Cfg;
|
||||
use crate::clean::clean_middle_path;
|
||||
@ -1384,8 +1383,8 @@ pub(crate) struct FnDecl {
|
||||
}
|
||||
|
||||
impl FnDecl {
|
||||
pub(crate) fn self_type(&self) -> Option<SelfTy> {
|
||||
self.inputs.values.get(0).and_then(|v| v.to_self())
|
||||
pub(crate) fn receiver_type(&self) -> Option<&Type> {
|
||||
self.inputs.values.get(0).and_then(|v| v.to_receiver())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1403,27 +1402,9 @@ pub(crate) struct Argument {
|
||||
pub(crate) is_const: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub(crate) enum SelfTy {
|
||||
SelfValue,
|
||||
SelfBorrowed(Option<Lifetime>, Mutability),
|
||||
SelfExplicit(Type),
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
pub(crate) fn to_self(&self) -> Option<SelfTy> {
|
||||
if self.name != kw::SelfLower {
|
||||
return None;
|
||||
}
|
||||
if self.type_.is_self_type() {
|
||||
return Some(SelfValue);
|
||||
}
|
||||
match self.type_ {
|
||||
BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
|
||||
Some(SelfBorrowed(lifetime.clone(), mutability))
|
||||
}
|
||||
_ => Some(SelfExplicit(self.type_.clone())),
|
||||
}
|
||||
pub(crate) fn to_receiver(&self) -> Option<&Type> {
|
||||
if self.name == kw::SelfLower { Some(&self.type_) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1477,6 +1458,8 @@ pub(crate) enum Type {
|
||||
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
|
||||
/// A type parameter.
|
||||
Generic(Symbol),
|
||||
/// The `Self` type.
|
||||
SelfTy,
|
||||
/// A primitive (aka, builtin) type.
|
||||
Primitive(PrimitiveType),
|
||||
/// A function pointer: `extern "ABI" fn(...) -> ...`
|
||||
@ -1571,6 +1554,8 @@ pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
|
||||
// If both sides are generic, this returns true.
|
||||
(_, Type::Generic(_)) => true,
|
||||
(Type::Generic(_), _) => false,
|
||||
// `Self` only matches itself.
|
||||
(Type::SelfTy, Type::SelfTy) => true,
|
||||
// Paths account for both the path itself and its generics.
|
||||
(Type::Path { path: a }, Type::Path { path: b }) => {
|
||||
a.def_id() == b.def_id()
|
||||
@ -1642,7 +1627,7 @@ pub(crate) fn is_assoc_ty(&self) -> bool {
|
||||
|
||||
pub(crate) fn is_self_type(&self) -> bool {
|
||||
match *self {
|
||||
Generic(name) => name == kw::SelfUpper,
|
||||
SelfTy => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1700,7 +1685,7 @@ pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
|
||||
Type::Pat(..) => PrimitiveType::Pat,
|
||||
RawPointer(..) => PrimitiveType::RawPointer,
|
||||
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
|
||||
Generic(_) | Infer | ImplTrait(_) => return None,
|
||||
Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
|
||||
};
|
||||
Primitive(t).def_id(cache)
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
|
||||
match path.res {
|
||||
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
|
||||
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
|
||||
Generic(kw::SelfUpper)
|
||||
Type::SelfTy
|
||||
}
|
||||
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
|
||||
_ => {
|
||||
|
@ -1006,6 +1006,7 @@ fn fmt_type<'cx>(
|
||||
|
||||
match *t {
|
||||
clean::Generic(name) => f.write_str(name.as_str()),
|
||||
clean::SelfTy => f.write_str("Self"),
|
||||
clean::Type::Path { ref path } => {
|
||||
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
||||
let did = path.def_id();
|
||||
@ -1452,29 +1453,22 @@ fn inner_full_print(
|
||||
|
||||
let last_input_index = self.inputs.values.len().checked_sub(1);
|
||||
for (i, input) in self.inputs.values.iter().enumerate() {
|
||||
if let Some(selfty) = input.to_self() {
|
||||
if let Some(selfty) = input.to_receiver() {
|
||||
match selfty {
|
||||
clean::SelfValue => {
|
||||
clean::SelfTy => {
|
||||
write!(f, "self")?;
|
||||
}
|
||||
clean::SelfBorrowed(Some(ref lt), mutability) => {
|
||||
write!(
|
||||
f,
|
||||
"{amp}{lifetime} {mutability}self",
|
||||
lifetime = lt.print(),
|
||||
mutability = mutability.print_with_space(),
|
||||
)?;
|
||||
clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
|
||||
write!(f, "{amp}")?;
|
||||
match lifetime {
|
||||
Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
|
||||
None => {}
|
||||
}
|
||||
clean::SelfBorrowed(None, mutability) => {
|
||||
write!(
|
||||
f,
|
||||
"{amp}{mutability}self",
|
||||
mutability = mutability.print_with_space(),
|
||||
)?;
|
||||
write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
|
||||
}
|
||||
clean::SelfExplicit(ref typ) => {
|
||||
_ => {
|
||||
write!(f, "self: ")?;
|
||||
typ.print(cx).fmt(f)?;
|
||||
selfty.print(cx).fmt(f)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
pub(crate) use self::context::*;
|
||||
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
|
||||
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
|
||||
use crate::clean::{self, ItemId, RenderedLink};
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
@ -1372,21 +1372,20 @@ fn render_deref_methods(
|
||||
|
||||
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
||||
let self_type_opt = match *item.kind {
|
||||
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
||||
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
||||
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
||||
clean::TyMethodItem(ref method) => method.decl.receiver_type(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(self_ty) = self_type_opt {
|
||||
let (by_mut_ref, by_box, by_value) = match self_ty {
|
||||
SelfTy::SelfBorrowed(_, mutability)
|
||||
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
|
||||
let (by_mut_ref, by_box, by_value) = match *self_ty {
|
||||
clean::Type::BorrowedRef { mutability, .. } => {
|
||||
(mutability == Mutability::Mut, false, false)
|
||||
}
|
||||
SelfTy::SelfExplicit(clean::Type::Path { path }) => {
|
||||
clean::Type::Path { ref path } => {
|
||||
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
|
||||
}
|
||||
SelfTy::SelfValue => (false, false, true),
|
||||
clean::Type::SelfTy => (false, false, true),
|
||||
_ => (false, false, false),
|
||||
};
|
||||
|
||||
|
@ -797,7 +797,11 @@ fn get_index_type_id(
|
||||
}
|
||||
}
|
||||
// Not supported yet
|
||||
clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
|
||||
clean::Type::Pat(..)
|
||||
| clean::Generic(_)
|
||||
| clean::SelfTy
|
||||
| clean::ImplTrait(_)
|
||||
| clean::Infer => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -850,11 +854,12 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
|
||||
// If this argument is a type parameter and not a trait bound or a type, we need to look
|
||||
// for its bounds.
|
||||
if let Type::Generic(arg_s) = *arg {
|
||||
match *arg {
|
||||
Type::Generic(arg_s) => {
|
||||
// First we check if the bounds are in a `where` predicate...
|
||||
let mut type_bounds = Vec::new();
|
||||
for where_pred in generics.where_predicates.iter().filter(|g| match g {
|
||||
WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
|
||||
WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
|
||||
_ => false,
|
||||
}) {
|
||||
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
|
||||
@ -909,7 +914,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
bindings: None,
|
||||
});
|
||||
}
|
||||
} else if let Type::ImplTrait(ref bounds) = *arg {
|
||||
}
|
||||
Type::ImplTrait(ref bounds) => {
|
||||
let mut type_bounds = Vec::new();
|
||||
for bound in bounds {
|
||||
if let Some(path) = bound.get_trait_path() {
|
||||
@ -928,7 +934,7 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
}
|
||||
}
|
||||
if is_return && !type_bounds.is_empty() {
|
||||
// In parameter position, `impl Trait` is a unique thing.
|
||||
// In return position, `impl Trait` is a unique thing.
|
||||
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
|
||||
} else {
|
||||
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
|
||||
@ -940,7 +946,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
bindings: None,
|
||||
});
|
||||
}
|
||||
} else if let Type::Slice(ref ty) = *arg {
|
||||
}
|
||||
Type::Slice(ref ty) => {
|
||||
let mut ty_generics = Vec::new();
|
||||
simplify_fn_type(
|
||||
self_,
|
||||
@ -954,7 +961,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
cache,
|
||||
);
|
||||
res.push(get_index_type(arg, ty_generics, rgen));
|
||||
} else if let Type::Array(ref ty, _) = *arg {
|
||||
}
|
||||
Type::Array(ref ty, _) => {
|
||||
let mut ty_generics = Vec::new();
|
||||
simplify_fn_type(
|
||||
self_,
|
||||
@ -968,7 +976,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
cache,
|
||||
);
|
||||
res.push(get_index_type(arg, ty_generics, rgen));
|
||||
} else if let Type::Tuple(ref tys) = *arg {
|
||||
}
|
||||
Type::Tuple(ref tys) => {
|
||||
let mut ty_generics = Vec::new();
|
||||
for ty in tys {
|
||||
simplify_fn_type(
|
||||
@ -984,7 +993,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
);
|
||||
}
|
||||
res.push(get_index_type(arg, ty_generics, rgen));
|
||||
} else if let Type::BareFunction(ref bf) = *arg {
|
||||
}
|
||||
Type::BareFunction(ref bf) => {
|
||||
let mut ty_generics = Vec::new();
|
||||
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
|
||||
simplify_fn_type(
|
||||
@ -1020,7 +1030,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
bindings: Some(ty_bindings),
|
||||
generics: Some(ty_generics),
|
||||
});
|
||||
} else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
|
||||
}
|
||||
Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
|
||||
let mut ty_generics = Vec::new();
|
||||
if mutability.is_mut() {
|
||||
ty_generics.push(RenderType {
|
||||
@ -1041,7 +1052,8 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
cache,
|
||||
);
|
||||
res.push(get_index_type(arg, ty_generics, rgen));
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
|
||||
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
|
||||
//
|
||||
@ -1156,6 +1168,7 @@ fn simplify_fn_type<'tcx, 'a>(
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_fn_constraint<'tcx, 'a>(
|
||||
|
@ -578,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
|
||||
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::Type::{
|
||||
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
|
||||
RawPointer, Slice, Tuple,
|
||||
RawPointer, SelfTy, Slice, Tuple,
|
||||
};
|
||||
|
||||
match ty {
|
||||
@ -588,6 +588,8 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
||||
traits: bounds.into_tcx(tcx),
|
||||
}),
|
||||
Generic(s) => Type::Generic(s.to_string()),
|
||||
// FIXME: add dedicated variant to json Type?
|
||||
SelfTy => Type::Generic("Self".to_owned()),
|
||||
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
|
||||
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
|
||||
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
|
||||
|
22
tests/rustdoc-js/self-is-not-generic.js
Normal file
22
tests/rustdoc-js/self-is-not-generic.js
Normal file
@ -0,0 +1,22 @@
|
||||
// exact-check
|
||||
|
||||
const EXPECTED = [
|
||||
{
|
||||
'query': 'A -> A',
|
||||
'others': [
|
||||
{ 'path': 'self_is_not_generic::Thing', 'name': 'from' }
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'A -> B',
|
||||
'others': [
|
||||
{ 'path': 'self_is_not_generic::Thing', 'name': 'try_from' }
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Combine -> Combine',
|
||||
'others': [
|
||||
{ 'path': 'self_is_not_generic::Combine', 'name': 'combine' }
|
||||
],
|
||||
}
|
||||
];
|
11
tests/rustdoc-js/self-is-not-generic.rs
Normal file
11
tests/rustdoc-js/self-is-not-generic.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub trait Combine {
|
||||
fn combine(&self, other: &Self) -> Self;
|
||||
}
|
||||
|
||||
pub struct Thing;
|
||||
|
||||
impl Combine for Thing {
|
||||
fn combine(&self, other: &Self) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user