From 025a2cda0ec511b6bc66f02dcddc408bf386e7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 23 Sep 2023 03:25:52 +0200 Subject: [PATCH] rustdoc: correctly render ret ty of cross-crate async fns --- src/librustdoc/clean/mod.rs | 21 +++++---- src/librustdoc/clean/types.rs | 44 +++++++++---------- tests/rustdoc/inline_cross/async-fn.rs | 19 ++++++++ .../inline_cross/auxiliary/async-fn.rs | 18 ++++++++ .../inline_cross/auxiliary/impl_trait_aux.rs | 6 --- tests/rustdoc/inline_cross/impl_trait.rs | 8 ---- 6 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 tests/rustdoc/inline_cross/async-fn.rs create mode 100644 tests/rustdoc/inline_cross/auxiliary/async-fn.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 190b1b038b6..4b53f7a6b7c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1107,10 +1107,7 @@ fn clean_function<'tcx>( clean_args_from_types_and_names(cx, sig.decl.inputs, names) } }; - let mut decl = clean_fn_decl_with_args(cx, sig.decl, args); - if sig.header.is_async() { - decl.output = decl.sugared_async_return_type(); - } + let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args); (generics, decl) }); Box::new(Function { decl, generics }) @@ -1161,12 +1158,16 @@ fn clean_args_from_types_and_body_id<'tcx>( fn clean_fn_decl_with_args<'tcx>( cx: &mut DocContext<'tcx>, decl: &hir::FnDecl<'tcx>, + header: Option<&hir::FnHeader>, args: Arguments, ) -> FnDecl { - let output = match decl.output { + let mut output = match decl.output { hir::FnRetTy::Return(typ) => clean_ty(typ, cx), hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()), }; + if let Some(header) = header && header.is_async() { + output = output.sugared_async_return_type(); + } FnDecl { inputs: args, output, c_variadic: decl.c_variadic } } @@ -1179,7 +1180,11 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( // We assume all empty tuples are default return type. This theoretically can discard `-> ()`, // but shouldn't change any code meaning. - let output = clean_middle_ty(sig.output(), cx, None, None); + let mut output = clean_middle_ty(sig.output(), cx, None, None); + + if let Some(did) = did && cx.tcx.asyncness(did).is_async() { + output = output.sugared_async_return_type(); + } FnDecl { output, @@ -2566,7 +2571,7 @@ fn clean_bare_fn_ty<'tcx>( .map(|x| clean_generic_param(cx, None, x)) .collect(); let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names); - let decl = clean_fn_decl_with_args(cx, bare_fn.decl, args); + let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args); (generic_params, decl) }); BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params } @@ -3077,7 +3082,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); let args = clean_args_from_types_and_names(cx, decl.inputs, names); - let decl = clean_fn_decl_with_args(cx, decl, args); + let decl = clean_fn_decl_with_args(cx, decl, None, args); (generics, decl) }); ForeignFunctionItem(Box::new(Function { decl, generics })) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ef7794cc41e..d422a0b9a7f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1380,28 +1380,6 @@ impl FnDecl { pub(crate) fn self_type(&self) -> Option { 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`, this function - /// will return `i32`. - /// - /// # Panics - /// - /// This function will panic if the return type does not match the expected sugaring for async - /// functions. - pub(crate) fn sugared_async_return_type(&self) -> Type { - if let Type::ImplTrait(v) = &self.output && - let [GenericBound::TraitBound(PolyTrait { trait_, .. }, _ )] = &v[..] - { - let bindings = trait_.bindings().unwrap(); - let ret_ty = bindings[0].term(); - let ty = ret_ty.ty().expect("Unexpected constant return term"); - ty.clone() - } else { - panic!("unexpected desugaring of async function") - } - } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -1613,6 +1591,28 @@ pub(crate) fn primitive_type(&self) -> Option { } } + /// Returns the sugared return type for an async function. + /// + /// For example, if the return type is `impl std::future::Future`, this function + /// will return `i32`. + /// + /// # Panics + /// + /// This function will panic if the return type does not match the expected sugaring for async + /// functions. + pub(crate) fn sugared_async_return_type(&self) -> Type { + if let Type::ImplTrait(v) = self && + let [GenericBound::TraitBound(PolyTrait { trait_, .. }, _ )] = &v[..] + { + let bindings = trait_.bindings().unwrap(); + let ret_ty = bindings[0].term(); + let ty = ret_ty.ty().expect("unexpected constant in async fn return term"); + ty.clone() + } else { + panic!("unexpected async fn return type") + } + } + /// Checks if this is a `T::Name` path for an associated type. pub(crate) fn is_assoc_ty(&self) -> bool { match self { diff --git a/tests/rustdoc/inline_cross/async-fn.rs b/tests/rustdoc/inline_cross/async-fn.rs new file mode 100644 index 00000000000..95e175aabd0 --- /dev/null +++ b/tests/rustdoc/inline_cross/async-fn.rs @@ -0,0 +1,19 @@ +// Regression test for issue #115760. +// Check that we render the correct return type of free and +// associated async functions reexported from external crates. + +// aux-crate:async_fn=async-fn.rs +// edition: 2021 +#![crate_name = "user"] + +// @has user/fn.load.html +// @has - '//pre[@class="rust item-decl"]' "pub async fn load() -> i32" +pub use async_fn::load; + +// @has user/trait.Load.html +// @has - '//*[@id="tymethod.run"]' 'async fn run(&self) -> i32' +pub use async_fn::Load; + +// @has user/struct.Loader.html +// @has - '//*[@id="method.run"]' 'async fn run(&self) -> i32' +pub use async_fn::Loader; diff --git a/tests/rustdoc/inline_cross/auxiliary/async-fn.rs b/tests/rustdoc/inline_cross/auxiliary/async-fn.rs new file mode 100644 index 00000000000..767564ed145 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/async-fn.rs @@ -0,0 +1,18 @@ +#![feature(async_fn_in_trait)] +// edition: 2021 + +pub async fn load() -> i32 { + 0 +} + +pub trait Load { + async fn run(&self) -> i32; +} + +pub struct Loader; + +impl Load for Loader { + async fn run(&self) -> i32 { + 1 + } +} diff --git a/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 19433c9682b..42cfc3dc319 100644 --- a/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -33,9 +33,3 @@ pub async fn async_fn() {} impl Foo { pub fn method<'a>(_x: impl Clone + Into> + 'a) {} } - -pub struct Bar; - -impl Bar { - pub async fn async_foo(&self) {} -} diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc/inline_cross/impl_trait.rs index b6a1552bc00..5c802c51486 100644 --- a/tests/rustdoc/inline_cross/impl_trait.rs +++ b/tests/rustdoc/inline_cross/impl_trait.rs @@ -33,15 +33,7 @@ // @!has - '//pre[@class="rust item-decl"]' 'where' pub use impl_trait_aux::func5; -// @has impl_trait/fn.async_fn.html -// @has - '//pre[@class="rust item-decl"]' "pub async fn async_fn()" -pub use impl_trait_aux::async_fn; - // @has impl_trait/struct.Foo.html // @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//*[@id="method.method"]//h4[@class="code-header"]' 'where' pub use impl_trait_aux::Foo; - -// @has impl_trait/struct.Bar.html -// @has - '//*[@id="method.async_foo"]' "pub async fn async_foo(" -pub use impl_trait_aux::Bar;