about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2019-02-10 21:45:12 +0100
committerGitHub <noreply@github.com>2019-02-10 21:45:12 +0100
commitcdbd07cc40bc0cedbf38ffb6b69465e0cff6eff6 (patch)
tree2cdfe4359051678d9c6b9077bc82008b47b8de10 /src
parenta74e4f7fd5fd0eac66a021bfb108942ad1ec3995 (diff)
parent4deb5959a3a2cbc189e26cb4b0c59a6707a10b45 (diff)
downloadrust-cdbd07cc40bc0cedbf38ffb6b69465e0cff6eff6.tar.gz
rust-cdbd07cc40bc0cedbf38ffb6b69465e0cff6eff6.zip
Rollup merge of #58203 - euclio:rustdoc-async, r=GuillaumeGomez
rustdoc: display sugared return types for async functions

Fixes #58027.
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/mod.rs39
-rw-r--r--src/librustdoc/html/format.rs23
-rw-r--r--src/librustdoc/html/render.rs8
-rw-r--r--src/test/rustdoc/async-fn.rs35
4 files changed, 88 insertions, 17 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bd0525583f2..d854488244f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -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)]
@@ -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 {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5a3e6984859..c03e679bc51 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -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;
@@ -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.
@@ -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();
@@ -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);
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index a85ac19286a..8e4d6b26c72 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -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};
@@ -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)
 }
@@ -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,
diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs
index a0b6c291260..ba4997a7f9b 100644
--- a/src/test/rustdoc/async-fn.rs
+++ b/src/test/rustdoc/async-fn.rs
@@ -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() {}
 }