From aac741a465a865576ce7ff0ddde4c16f1da64f62 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Dec 2024 18:42:04 +0000 Subject: [PATCH] Unsafe binder support in rustdoc --- src/librustdoc/clean/mod.rs | 25 +++++++++++++++++--- src/librustdoc/clean/types.rs | 12 ++++++++-- src/librustdoc/html/format.rs | 17 +++++++++---- src/librustdoc/html/render/search_index.rs | 3 ++- src/librustdoc/json/conversions.rs | 4 +++- tests/rustdoc/auxiliary/unsafe-binder-dep.rs | 4 ++++ tests/rustdoc/unsafe-binder.rs | 15 ++++++++++++ 7 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 tests/rustdoc/auxiliary/unsafe-binder-dep.rs create mode 100644 tests/rustdoc/unsafe-binder.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3c9e0914b59d7..0f84b43866290 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8c7ab925577df..3c4fad4bca97e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -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), + + UnsafeBinder(Box), } 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, + pub(crate) ty: Type, +} + #[derive(Clone, Debug)] pub(crate) struct Static { pub(crate) type_: Box, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 136002b8e155b..621abd535010f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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<" })?; + f.write_str(keyword)?; + f.write_str(if f.alternate() { "<" } else { "<" })?; comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?; f.write_str(if f.alternate() { "> " } else { "> " })?; } @@ -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 { "" }; diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index fe2e155c9ba7a..66c52bec4bad7 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -900,7 +900,8 @@ fn get_index_type_id( | clean::Generic(_) | clean::SelfTy | clean::ImplTrait(_) - | clean::Infer => None, + | clean::Infer + | clean::UnsafeBinder(_) => None, } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7f072aa7e2fc4..7fcdfe3fb22ea 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -573,7 +573,7 @@ impl FromClean 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 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!(), } } } diff --git a/tests/rustdoc/auxiliary/unsafe-binder-dep.rs b/tests/rustdoc/auxiliary/unsafe-binder-dep.rs new file mode 100644 index 0000000000000..65aa9032fed19 --- /dev/null +++ b/tests/rustdoc/auxiliary/unsafe-binder-dep.rs @@ -0,0 +1,4 @@ +#![feature(unsafe_binders)] +#![allow(incomplete_features)] + +pub fn woof() -> unsafe<'a> &'a str { todo!() } diff --git a/tests/rustdoc/unsafe-binder.rs b/tests/rustdoc/unsafe-binder.rs new file mode 100644 index 0000000000000..621c3dadc72ee --- /dev/null +++ b/tests/rustdoc/unsafe-binder.rs @@ -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!() }