Skip to content

Commit

Permalink
Rollup merge of rust-lang#79991 - camelid:rustdoc-for-lifetime, r=Gui…
Browse files Browse the repository at this point in the history
…llaumeGomez,jyn514

rustdoc: Render HRTB correctly for bare functions

The angle brackets were not rendered, so code like this:

    some_func: for<'a> fn(val: &'a i32) -> i32

would be rendered as:

    some_func: fn'a(val: &'a i32) -> i32

However, rendering with angle brackets is still invalid syntax:

    some_func: fn<'a>(val: &'a i32) -> i32

so now it renders correctly as:

    some_func: for<'a> fn(val: &'a i32) -> i32

-----

However, note that this code:

    some_trait: dyn for<'a> Trait<'a>

will still render as:

    some_trait: dyn Trait<'a>

which is not invalid syntax, but is still unclear. Unfortunately I think
it's hard to fix that case because there isn't enough information in the
`rustdoc::clean::Type` that this code operates on. Perhaps that case can
be fixed in a later PR.

r? `@jyn514`
  • Loading branch information
Dylan-DPC authored Jan 28, 2021
2 parents b42f4ef + cd8dcee commit 6f47762
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
21 changes: 15 additions & 6 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ fn fmt_type(
use_absolute: bool,
cache: &Cache,
) -> fmt::Result {
debug!("fmt_type(t = {:?})", t);

match *t {
clean::Generic(name) => write!(f, "{}", name),
clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
Expand All @@ -675,21 +677,22 @@ fn fmt_type(
if f.alternate() {
write!(
f,
"{}{:#}fn{:#}{:#}",
"{:#}{}{:#}fn{:#}",
decl.print_hrtb_with_space(cache),
decl.unsafety.print_with_space(),
print_abi_with_space(decl.abi),
decl.print_generic_params(cache),
decl.decl.print(cache)
)
} else {
write!(
f,
"{}{}",
"{}{}{}",
decl.print_hrtb_with_space(cache),
decl.unsafety.print_with_space(),
print_abi_with_space(decl.abi)
)?;
primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
write!(f, "{}{}", decl.print_generic_params(cache), decl.decl.print(cache))
write!(f, "{}", decl.decl.print(cache))
}
}
clean::Tuple(ref typs) => {
Expand Down Expand Up @@ -992,8 +995,14 @@ impl clean::FnRetTy {
}

impl clean::BareFunctionDecl {
fn print_generic_params<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
comma_sep(self.generic_params.iter().map(move |g| g.print(cache)))
fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
display_fn(move |f| {
if !self.generic_params.is_empty() {
write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache))))
} else {
Ok(())
}
})
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/test/rustdoc/fn-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// ignore-tidy-linelength

#![crate_name = "foo"]
#![crate_type = "lib"]

pub struct Foo<'a, T> {
pub generic: fn(val: &T) -> T,

pub lifetime: fn(val: &'a i32) -> i32,
pub hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32),
}

// @has 'foo/struct.Foo.html' '//span[@id="structfield.generic"]' "generic: fn(val: &T) -> T"
// @has 'foo/struct.Foo.html' '//span[@id="structfield.lifetime"]' "lifetime: fn(val: &'a i32) -> i32"
// @has 'foo/struct.Foo.html' '//span[@id="structfield.hrtb_lifetime"]' "hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32)"
14 changes: 14 additions & 0 deletions src/test/rustdoc/for-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// ignore-tidy-linelength

#![crate_name = "foo"]
#![crate_type = "lib"]

pub struct Foo {
pub some_func: for<'a> fn(val: &'a i32) -> i32,
pub some_trait: dyn for<'a> Trait<'a>,
}

// @has foo/struct.Foo.html '//span[@id="structfield.some_func"]' "some_func: for<'a> fn(val: &'a i32) -> i32"
// @has foo/struct.Foo.html '//span[@id="structfield.some_trait"]' "some_trait: dyn Trait<'a>"

pub trait Trait<'a> {}

0 comments on commit 6f47762

Please sign in to comment.