Unsafe binder support in rustdoc

This commit is contained in:
Michael Goulet 2024-12-28 18:42:04 +00:00
parent 7f75bfa1ad
commit aac741a465
7 changed files with 68 additions and 12 deletions

View file

@ -1844,8 +1844,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
DynTrait(bounds, lifetime)
}
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
TyKind::UnsafeBinder(..) => {
unimplemented!("unsafe binders are not supported yet")
TyKind::UnsafeBinder(unsafe_binder_ty) => {
UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
}
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer
@ -2075,6 +2075,11 @@ pub(crate) fn clean_middle_ty<'tcx>(
abi: sig.abi(),
}))
}
ty::UnsafeBinder(inner) => {
let generic_params = clean_bound_vars(inner.bound_vars());
let ty = clean_middle_ty(inner.into(), cx, None, None);
UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, ty }))
}
ty::Adt(def, args) => {
let did = def.did();
let kind = match def.adt_kind() {
@ -2253,7 +2258,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
}
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
ty::Closure(..) => panic!("Closure"),
ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
ty::Coroutine(..) => panic!("Coroutine"),
@ -2564,6 +2568,21 @@ fn clean_bare_fn_ty<'tcx>(
BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
}
fn clean_unsafe_binder_ty<'tcx>(
unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>,
cx: &mut DocContext<'tcx>,
) -> UnsafeBinderTy {
// NOTE: generics must be cleaned before args
let generic_params = unsafe_binder_ty
.generic_params
.iter()
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x))
.collect();
let ty = clean_ty(unsafe_binder_ty.inner_ty, cx);
UnsafeBinderTy { generic_params, ty }
}
pub(crate) fn reexport_chain(
tcx: TyCtxt<'_>,
import_def_id: LocalDefId,

View file

@ -32,7 +32,7 @@ use {rustc_ast as ast, rustc_hir as hir};
pub(crate) use self::ItemKind::*;
pub(crate) use self::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, SelfTy, Slice, Tuple,
RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
};
use crate::clean::cfg::Cfg;
use crate::clean::clean_middle_path;
@ -1511,6 +1511,8 @@ pub(crate) enum Type {
/// An `impl Trait`: `impl TraitA + TraitB + ...`
ImplTrait(Vec<GenericBound>),
UnsafeBinder(Box<UnsafeBinderTy>),
}
impl Type {
@ -1703,7 +1705,7 @@ impl Type {
Type::Pat(..) => PrimitiveType::Pat,
RawPointer(..) => PrimitiveType::RawPointer,
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
};
Primitive(t).def_id(cache)
}
@ -2343,6 +2345,12 @@ pub(crate) struct BareFunctionDecl {
pub(crate) abi: ExternAbi,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct UnsafeBinderTy {
pub(crate) generic_params: Vec<GenericParamDef>,
pub(crate) ty: Type,
}
#[derive(Clone, Debug)]
pub(crate) struct Static {
pub(crate) type_: Box<Type>,

View file

@ -282,7 +282,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
match pred {
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?;
print_higher_ranked_params_with_space(bound_params, cx, "for")
.fmt(f)?;
ty.print(cx).fmt(f)?;
f.write_str(":")?;
if !bounds.is_empty() {
@ -386,7 +387,7 @@ impl clean::ConstantKind {
impl clean::PolyTrait {
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
display_fn(move |f| {
print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?;
print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
self.trait_.print(cx).fmt(f)
})
}
@ -968,10 +969,12 @@ fn tybounds<'a, 'tcx: 'a>(
fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
params: &'a [clean::GenericParamDef],
cx: &'a Context<'tcx>,
keyword: &'static str,
) -> impl Display + 'a + Captures<'tcx> {
display_fn(move |f| {
if !params.is_empty() {
f.write_str(if f.alternate() { "for<" } else { "for&lt;" })?;
f.write_str(keyword)?;
f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?;
f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
}
@ -1027,7 +1030,7 @@ fn fmt_type(
primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx)
}
clean::BareFunction(ref decl) => {
print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
print_higher_ranked_params_with_space(&decl.generic_params, cx, "for").fmt(f)?;
decl.safety.print_with_space().fmt(f)?;
print_abi_with_space(decl.abi).fmt(f)?;
if f.alternate() {
@ -1037,6 +1040,10 @@ fn fmt_type(
}
decl.decl.print(cx).fmt(f)
}
clean::UnsafeBinder(ref binder) => {
print_higher_ranked_params_with_space(&binder.generic_params, cx, "unsafe").fmt(f)?;
binder.ty.print(cx).fmt(f)
}
clean::Tuple(ref typs) => match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
[one] => {
@ -1354,7 +1361,7 @@ impl clean::Impl {
// Hardcoded anchor library/core/src/primitive_docs.rs
// Link should match `# Trait implementations`
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx, "for").fmt(f)?;
bare_fn.safety.print_with_space().fmt(f)?;
print_abi_with_space(bare_fn.abi).fmt(f)?;
let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };

View file

@ -900,7 +900,8 @@ fn get_index_type_id(
| clean::Generic(_)
| clean::SelfTy
| clean::ImplTrait(_)
| clean::Infer => None,
| clean::Infer
| clean::UnsafeBinder(_) => None,
}
}

View file

@ -573,7 +573,7 @@ impl FromClean<clean::Type> for Type {
fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self {
use clean::Type::{
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, SelfTy, Slice, Tuple,
RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
};
match ty {
@ -613,6 +613,8 @@ impl FromClean<clean::Type> for Type {
self_type: Box::new(self_type.into_json(renderer)),
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
},
// FIXME(unsafe_binder): Implement rustdoc-json.
UnsafeBinder(_) => todo!(),
}
}
}

View file

@ -0,0 +1,4 @@
#![feature(unsafe_binders)]
#![allow(incomplete_features)]
pub fn woof() -> unsafe<'a> &'a str { todo!() }

View file

@ -0,0 +1,15 @@
//@ aux-build:unsafe-binder-dep.rs
#![feature(unsafe_binders)]
#![allow(incomplete_features)]
extern crate unsafe_binder_dep;
//@ has 'unsafe_binder/fn.woof.html' //pre "fn woof() -> unsafe<'a> &'a str"
pub use unsafe_binder_dep::woof;
//@ has 'unsafe_binder/fn.meow.html' //pre "fn meow() -> unsafe<'a> &'a str"
pub fn meow() -> unsafe<'a> &'a str { todo!() }
//@ has 'unsafe_binder/fn.meow_squared.html' //pre "fn meow_squared() -> unsafe<'b, 'a> &'a &'b str"
pub fn meow_squared() -> unsafe<'b, 'a> &'a &'b str { todo!() }