Skip to content

Commit

Permalink
Rollup merge of rust-lang#58203 - euclio:rustdoc-async, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
rustdoc: display sugared return types for async functions

Fixes rust-lang#58027.
  • Loading branch information
GuillaumeGomez authored Feb 10, 2019
2 parents a74e4f7 + 4deb595 commit cdbd07c
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 17 deletions.
39 changes: 39 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,30 @@ impl FnDecl {
pub fn self_type(&self) -> Option<SelfTy> {
self.inputs.values.get(0).and_then(|v| v.to_self())
}

/// Returns the sugared return type for an async function.
///
/// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
/// will return `i32`.
///
/// # Panics
///
/// This function will panic if the return type does not match the expected sugaring for async
/// functions.
pub fn sugared_async_return_type(&self) -> FunctionRetTy {
match &self.output {
FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
match &bounds[0] {
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
let bindings = trait_.bindings().unwrap();
FunctionRetTy::Return(bindings[0].ty.clone())
}
_ => panic!("unexpected desugaring of async function"),
}
}
_ => panic!("unexpected desugaring of async function"),
}
}
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
Expand Down Expand Up @@ -2282,6 +2306,21 @@ impl Type {
_ => None,
}
}

pub fn bindings(&self) -> Option<&[TypeBinding]> {
match *self {
ResolvedPath { ref path, .. } => {
path.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
Some(&**bindings)
} else {
None
}
})
}
_ => None
}
}
}

impl GetDefId for Type {
Expand Down
23 changes: 16 additions & 7 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! assume that HTML output is desired, although it may be possible to redesign
//! them in the future to instead emit any format desired.

use std::borrow::Cow;
use std::fmt;

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

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

/// Wrapper struct for emitting a where clause from Generics.
Expand Down Expand Up @@ -829,9 +832,9 @@ impl fmt::Display for clean::FnDecl {
}
}

impl<'a> fmt::Display for Method<'a> {
impl<'a> fmt::Display for Function<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &Method { decl, name_len, indent } = self;
let &Function { decl, name_len, indent, asyncness } = self;
let amp = if f.alternate() { "&" } else { "&amp;" };
let mut args = String::new();
let mut args_plain = String::new();
Expand Down Expand Up @@ -891,11 +894,17 @@ impl<'a> fmt::Display for Method<'a> {
args_plain.push_str(", ...");
}

let arrow_plain = format!("{:#}", decl.output);
let output = if let hir::IsAsync::Async = asyncness {
Cow::Owned(decl.sugared_async_return_type())
} else {
Cow::Borrowed(&decl.output)
};

let arrow_plain = format!("{:#}", &output);
let arrow = if f.alternate() {
format!("{:#}", decl.output)
format!("{:#}", &output)
} else {
decl.output.to_string()
output.to_string()
};

let pad = " ".repeat(name_len);
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use fold::DocFolder;
use html::escape::Escape;
use html::format::{AsyncSpace, ConstnessSpace};
use html::format::{GenericBounds, WhereClause, href, AbiSpace};
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
use html::format::{VisSpace, Function, UnsafetySpace, MutableSpace};
use html::format::fmt_impl_for_trait_page;
use html::item_type::ItemType;
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
Expand Down Expand Up @@ -2977,10 +2977,11 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
name = it.name.as_ref().unwrap(),
generics = f.generics,
where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
decl = Method {
decl = Function {
decl: &f.decl,
name_len,
indent: 0,
asyncness: f.header.asyncness,
})?;
document(w, cx, it)
}
Expand Down Expand Up @@ -3424,10 +3425,11 @@ fn render_assoc_item(w: &mut fmt::Formatter,
href = href,
name = name,
generics = *g,
decl = Method {
decl = Function {
decl: d,
name_len: head_len,
indent,
asyncness: header.asyncness,
},
where_clause = WhereClause {
gens: g,
Expand Down
35 changes: 28 additions & 7 deletions src/test/rustdoc/async-fn.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
// edition:2018
// compile-flags:-Z unstable-options

// FIXME: once `--edition` is stable in rustdoc, remove that `compile-flags` directive

#![feature(async_await, futures_api)]

// @has async_fn/struct.S.html
// @has - '//code' 'pub async fn f()'
pub struct S;
// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
pub async fn foo() -> Option<Foo> {
None
}

// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32'
pub async fn bar(a: i32, b: i32) -> i32 {
0
}

// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz<T>(a: T) -> T'
pub async fn baz<T>(a: T) -> T {
a
}

trait Bar {}

impl Bar for () {}

// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar'
pub async fn quux() -> impl Bar {
()
}

// @has async_fn/struct.Foo.html
// @matches - '//code' 'pub async fn f\(\)$'
pub struct Foo;

impl S {
impl Foo {
pub async fn f() {}
}

0 comments on commit cdbd07c

Please sign in to comment.