Skip to content

Commit 4deb595

Browse files
committed
display sugared return types for async functions
1 parent d30b99f commit 4deb595

File tree

4 files changed

+88
-17
lines changed

4 files changed

+88
-17
lines changed

src/librustdoc/clean/mod.rs

+39
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,30 @@ impl FnDecl {
17071707
pub fn self_type(&self) -> Option<SelfTy> {
17081708
self.inputs.values.get(0).and_then(|v| v.to_self())
17091709
}
1710+
1711+
/// Returns the sugared return type for an async function.
1712+
///
1713+
/// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1714+
/// will return `i32`.
1715+
///
1716+
/// # Panics
1717+
///
1718+
/// This function will panic if the return type does not match the expected sugaring for async
1719+
/// functions.
1720+
pub fn sugared_async_return_type(&self) -> FunctionRetTy {
1721+
match &self.output {
1722+
FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
1723+
match &bounds[0] {
1724+
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
1725+
let bindings = trait_.bindings().unwrap();
1726+
FunctionRetTy::Return(bindings[0].ty.clone())
1727+
}
1728+
_ => panic!("unexpected desugaring of async function"),
1729+
}
1730+
}
1731+
_ => panic!("unexpected desugaring of async function"),
1732+
}
1733+
}
17101734
}
17111735

17121736
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
@@ -2265,6 +2289,21 @@ impl Type {
22652289
_ => None,
22662290
}
22672291
}
2292+
2293+
pub fn bindings(&self) -> Option<&[TypeBinding]> {
2294+
match *self {
2295+
ResolvedPath { ref path, .. } => {
2296+
path.segments.last().and_then(|seg| {
2297+
if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2298+
Some(&**bindings)
2299+
} else {
2300+
None
2301+
}
2302+
})
2303+
}
2304+
_ => None
2305+
}
2306+
}
22682307
}
22692308

22702309
impl GetDefId for Type {

src/librustdoc/html/format.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! assume that HTML output is desired, although it may be possible to redesign
66
//! them in the future to instead emit any format desired.
77
8+
use std::borrow::Cow;
89
use std::fmt;
910

1011
use rustc::hir::def_id::DefId;
@@ -44,14 +45,16 @@ pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
4445
pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
4546
pub struct AbiSpace(pub Abi);
4647

47-
/// Wrapper struct for properly emitting a method declaration.
48-
pub struct Method<'a> {
48+
/// Wrapper struct for properly emitting a function or method declaration.
49+
pub struct Function<'a> {
4950
/// The declaration to emit.
5051
pub decl: &'a clean::FnDecl,
5152
/// The length of the function's "name", used to determine line-wrapping.
5253
pub name_len: usize,
5354
/// The number of spaces to indent each successive line with, if line-wrapping is necessary.
5455
pub indent: usize,
56+
/// Whether the function is async or not.
57+
pub asyncness: hir::IsAsync,
5558
}
5659

5760
/// Wrapper struct for emitting a where clause from Generics.
@@ -829,9 +832,9 @@ impl fmt::Display for clean::FnDecl {
829832
}
830833
}
831834

832-
impl<'a> fmt::Display for Method<'a> {
835+
impl<'a> fmt::Display for Function<'a> {
833836
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
834-
let &Method { decl, name_len, indent } = self;
837+
let &Function { decl, name_len, indent, asyncness } = self;
835838
let amp = if f.alternate() { "&" } else { "&amp;" };
836839
let mut args = String::new();
837840
let mut args_plain = String::new();
@@ -891,11 +894,17 @@ impl<'a> fmt::Display for Method<'a> {
891894
args_plain.push_str(", ...");
892895
}
893896

894-
let arrow_plain = format!("{:#}", decl.output);
897+
let output = if let hir::IsAsync::Async = asyncness {
898+
Cow::Owned(decl.sugared_async_return_type())
899+
} else {
900+
Cow::Borrowed(&decl.output)
901+
};
902+
903+
let arrow_plain = format!("{:#}", &output);
895904
let arrow = if f.alternate() {
896-
format!("{:#}", decl.output)
905+
format!("{:#}", &output)
897906
} else {
898-
decl.output.to_string()
907+
output.to_string()
899908
};
900909

901910
let pad = " ".repeat(name_len);

src/librustdoc/html/render.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use fold::DocFolder;
6262
use html::escape::Escape;
6363
use html::format::{AsyncSpace, ConstnessSpace};
6464
use html::format::{GenericBounds, WhereClause, href, AbiSpace};
65-
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
65+
use html::format::{VisSpace, Function, UnsafetySpace, MutableSpace};
6666
use html::format::fmt_impl_for_trait_page;
6767
use html::item_type::ItemType;
6868
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
@@ -2963,10 +2963,11 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
29632963
name = it.name.as_ref().unwrap(),
29642964
generics = f.generics,
29652965
where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
2966-
decl = Method {
2966+
decl = Function {
29672967
decl: &f.decl,
29682968
name_len,
29692969
indent: 0,
2970+
asyncness: f.header.asyncness,
29702971
})?;
29712972
document(w, cx, it)
29722973
}
@@ -3410,10 +3411,11 @@ fn render_assoc_item(w: &mut fmt::Formatter,
34103411
href = href,
34113412
name = name,
34123413
generics = *g,
3413-
decl = Method {
3414+
decl = Function {
34143415
decl: d,
34153416
name_len: head_len,
34163417
indent,
3418+
asyncness: header.asyncness,
34173419
},
34183420
where_clause = WhereClause {
34193421
gens: g,

src/test/rustdoc/async-fn.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
// edition:2018
2-
// compile-flags:-Z unstable-options
3-
4-
// FIXME: once `--edition` is stable in rustdoc, remove that `compile-flags` directive
52

63
#![feature(async_await, futures_api)]
74

8-
// @has async_fn/struct.S.html
9-
// @has - '//code' 'pub async fn f()'
10-
pub struct S;
5+
// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
6+
pub async fn foo() -> Option<Foo> {
7+
None
8+
}
9+
10+
// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32'
11+
pub async fn bar(a: i32, b: i32) -> i32 {
12+
0
13+
}
14+
15+
// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz<T>(a: T) -> T'
16+
pub async fn baz<T>(a: T) -> T {
17+
a
18+
}
19+
20+
trait Bar {}
21+
22+
impl Bar for () {}
23+
24+
// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar'
25+
pub async fn quux() -> impl Bar {
26+
()
27+
}
28+
29+
// @has async_fn/struct.Foo.html
30+
// @matches - '//code' 'pub async fn f\(\)$'
31+
pub struct Foo;
1132

12-
impl S {
33+
impl Foo {
1334
pub async fn f() {}
1435
}

0 commit comments

Comments
 (0)