Skip to content

Commit 54f1a12

Browse files
Unsafe binder support in rustdoc
1 parent 3c1e750 commit 54f1a12

File tree

7 files changed

+66
-12
lines changed

7 files changed

+66
-12
lines changed

src/librustdoc/clean/mod.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -1846,8 +1846,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
18461846
DynTrait(bounds, lifetime)
18471847
}
18481848
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
1849-
TyKind::UnsafeBinder(..) => {
1850-
unimplemented!("unsafe binders are not supported yet")
1849+
TyKind::UnsafeBinder(unsafe_binder_ty) => {
1850+
UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
18511851
}
18521852
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
18531853
TyKind::Infer
@@ -2077,6 +2077,11 @@ pub(crate) fn clean_middle_ty<'tcx>(
20772077
abi: sig.abi(),
20782078
}))
20792079
}
2080+
ty::UnsafeBinder(inner) => {
2081+
let generic_params = clean_bound_vars(inner.bound_vars());
2082+
let ty = clean_middle_ty(inner.into(), cx, None, None);
2083+
UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, ty }))
2084+
}
20802085
ty::Adt(def, args) => {
20812086
let did = def.did();
20822087
let kind = match def.adt_kind() {
@@ -2255,7 +2260,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
22552260
}
22562261
}
22572262

2258-
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
22592263
ty::Closure(..) => panic!("Closure"),
22602264
ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
22612265
ty::Coroutine(..) => panic!("Coroutine"),
@@ -2566,6 +2570,21 @@ fn clean_bare_fn_ty<'tcx>(
25662570
BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
25672571
}
25682572

2573+
fn clean_unsafe_binder_ty<'tcx>(
2574+
unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>,
2575+
cx: &mut DocContext<'tcx>,
2576+
) -> UnsafeBinderTy {
2577+
// NOTE: generics must be cleaned before args
2578+
let generic_params = unsafe_binder_ty
2579+
.generic_params
2580+
.iter()
2581+
.filter(|p| !is_elided_lifetime(p))
2582+
.map(|x| clean_generic_param(cx, None, x))
2583+
.collect();
2584+
let ty = clean_ty(unsafe_binder_ty.inner_ty, cx);
2585+
UnsafeBinderTy { generic_params, ty }
2586+
}
2587+
25692588
pub(crate) fn reexport_chain(
25702589
tcx: TyCtxt<'_>,
25712590
import_def_id: LocalDefId,

src/librustdoc/clean/types.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use {rustc_ast as ast, rustc_hir as hir};
3232
pub(crate) use self::ItemKind::*;
3333
pub(crate) use self::Type::{
3434
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
35-
RawPointer, SelfTy, Slice, Tuple,
35+
RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
3636
};
3737
use crate::clean::cfg::Cfg;
3838
use crate::clean::clean_middle_path;
@@ -1511,6 +1511,8 @@ pub(crate) enum Type {
15111511

15121512
/// An `impl Trait`: `impl TraitA + TraitB + ...`
15131513
ImplTrait(Vec<GenericBound>),
1514+
1515+
UnsafeBinder(Box<UnsafeBinderTy>),
15141516
}
15151517

15161518
impl Type {
@@ -1703,7 +1705,7 @@ impl Type {
17031705
Type::Pat(..) => PrimitiveType::Pat,
17041706
RawPointer(..) => PrimitiveType::RawPointer,
17051707
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
1706-
Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
1708+
Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
17071709
};
17081710
Primitive(t).def_id(cache)
17091711
}
@@ -2343,6 +2345,12 @@ pub(crate) struct BareFunctionDecl {
23432345
pub(crate) abi: ExternAbi,
23442346
}
23452347

2348+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2349+
pub(crate) struct UnsafeBinderTy {
2350+
pub(crate) generic_params: Vec<GenericParamDef>,
2351+
pub(crate) ty: Type,
2352+
}
2353+
23462354
#[derive(Clone, Debug)]
23472355
pub(crate) struct Static {
23482356
pub(crate) type_: Box<Type>,

src/librustdoc/html/format.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
282282

283283
match pred {
284284
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
285-
print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?;
285+
print_higher_ranked_params_with_space(bound_params, cx, "for")
286+
.fmt(f)?;
286287
ty.print(cx).fmt(f)?;
287288
f.write_str(":")?;
288289
if !bounds.is_empty() {
@@ -386,7 +387,7 @@ impl clean::ConstantKind {
386387
impl clean::PolyTrait {
387388
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
388389
display_fn(move |f| {
389-
print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?;
390+
print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
390391
self.trait_.print(cx).fmt(f)
391392
})
392393
}
@@ -968,10 +969,12 @@ fn tybounds<'a, 'tcx: 'a>(
968969
fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
969970
params: &'a [clean::GenericParamDef],
970971
cx: &'a Context<'tcx>,
972+
keyword: &'static str,
971973
) -> impl Display + 'a + Captures<'tcx> {
972974
display_fn(move |f| {
973975
if !params.is_empty() {
974-
f.write_str(if f.alternate() { "for<" } else { "for&lt;" })?;
976+
f.write_str(keyword)?;
977+
f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
975978
comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?;
976979
f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
977980
}
@@ -1027,7 +1030,7 @@ fn fmt_type(
10271030
primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx)
10281031
}
10291032
clean::BareFunction(ref decl) => {
1030-
print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
1033+
print_higher_ranked_params_with_space(&decl.generic_params, cx, "for").fmt(f)?;
10311034
decl.safety.print_with_space().fmt(f)?;
10321035
print_abi_with_space(decl.abi).fmt(f)?;
10331036
if f.alternate() {
@@ -1037,6 +1040,11 @@ fn fmt_type(
10371040
}
10381041
decl.decl.print(cx).fmt(f)
10391042
}
1043+
clean::UnsafeBinder(ref binder) => {
1044+
// FIXME(unsafe_binders): This should print `unsafe<...>`
1045+
print_higher_ranked_params_with_space(&binder.generic_params, cx, "unsafe").fmt(f)?;
1046+
binder.ty.print(cx).fmt(f)
1047+
}
10401048
clean::Tuple(ref typs) => match &typs[..] {
10411049
&[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
10421050
[one] => {
@@ -1354,7 +1362,7 @@ impl clean::Impl {
13541362
// Hardcoded anchor library/core/src/primitive_docs.rs
13551363
// Link should match `# Trait implementations`
13561364

1357-
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
1365+
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx, "for").fmt(f)?;
13581366
bare_fn.safety.print_with_space().fmt(f)?;
13591367
print_abi_with_space(bare_fn.abi).fmt(f)?;
13601368
let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };

src/librustdoc/html/render/search_index.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,8 @@ fn get_index_type_id(
900900
| clean::Generic(_)
901901
| clean::SelfTy
902902
| clean::ImplTrait(_)
903-
| clean::Infer => None,
903+
| clean::Infer
904+
| clean::UnsafeBinder(_) => None,
904905
}
905906
}
906907

src/librustdoc/json/conversions.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ impl FromClean<clean::Type> for Type {
573573
fn from_clean(ty: clean::Type, renderer: &JsonRenderer<'_>) -> Self {
574574
use clean::Type::{
575575
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
576-
RawPointer, SelfTy, Slice, Tuple,
576+
RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
577577
};
578578

579579
match ty {
@@ -613,6 +613,8 @@ impl FromClean<clean::Type> for Type {
613613
self_type: Box::new(self_type.into_json(renderer)),
614614
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
615615
},
616+
// FIXME(unsafe_binder): Implement rustdoc-json.
617+
UnsafeBinder(_) => todo!(),
616618
}
617619
}
618620
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![feature(unsafe_binders)]
2+
#![allow(incomplete_features)]
3+
4+
pub fn woof() -> unsafe<'a> &'a str { todo!() }

tests/rustdoc/unsafe-binder.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ aux-build:unsafe-binder-dep.rs
2+
3+
#![feature(unsafe_binders)]
4+
#![allow(incomplete_features)]
5+
6+
extern crate unsafe_binder_dep;
7+
8+
//@ has 'unsafe_binder/fn.woof.html' //pre "fn woof() -> unsafe<'a> &'a str"
9+
pub use unsafe_binder_dep::woof;
10+
11+
//@ has 'unsafe_binder/fn.meow.html' //pre "fn meow() -> unsafe<'a> &'a str"
12+
pub fn meow() -> unsafe<'a> &'a str { todo!() }

0 commit comments

Comments
 (0)