From 7456253352678c9658f58e7e17b6740429dee4f8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 Mar 2023 03:18:38 +0000 Subject: [PATCH] Infer async block return type from future expectation --- compiler/rustc_hir_typeck/src/closure.rs | 30 +++++++++++++++---- tests/ui/async-await/expectation.rs | 11 +++++++ tests/ui/impl-trait/issues/issue-78722.rs | 2 +- tests/ui/impl-trait/issues/issue-78722.stderr | 12 ++++---- tests/ui/traits/new-solver/async.fail.stderr | 16 +++------- tests/ui/traits/new-solver/async.rs | 2 +- 6 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 tests/ui/async-await/expectation.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index ec391ea80f48b..4bc99a6ed09f3 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -293,7 +293,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let gen_trait = tcx.lang_items().gen_trait(); let is_gen = gen_trait == Some(trait_def_id); - if !is_fn && !is_gen { + let future_trait = tcx.lang_items().future_trait(); + let is_future = future_trait == Some(trait_def_id); + + if !(is_fn || is_gen || is_future) { debug!("not fn or generator"); return None; } @@ -305,6 +308,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } + // Since this is a return parameter type it is safe to unwrap. + let ret_param_ty = projection.skip_binder().term.ty().unwrap(); + let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); + debug!(?ret_param_ty); + let input_tys = if is_fn { let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); @@ -314,17 +322,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &ty::Tuple(tys) => tys, _ => return None, } + } else if is_future { + // HACK: Skip infer vars to `ui/generic-associated-types/issue-89008.rs` pass. + // Otherwise, we end up with inferring the closure signature to be + // `fn() -> Empty` instead of `fn() -> Self::LineStream<'a, Repr>` and + // opaque type inference gets bungled. Similarly, skip opaques, because we don't + // replace them with infer vars, and opaque type inference gets bungled in + // `async fn ..() -> impl Trait {}` cases. + if ret_param_ty.is_ty_var() || ret_param_ty.has_opaque_types() { + return None; + } + + let resume_ty_def_id = self.tcx.require_lang_item(hir::LangItem::ResumeTy, cause_span); + self.tcx.mk_type_list(&[self + .tcx + .mk_adt(self.tcx.adt_def(resume_ty_def_id), ty::List::empty())]) } else { // Generators with a `()` resume type may be defined with 0 or 1 explicit arguments, // else they must have exactly 1 argument. For now though, just give up in this case. return None; }; - // Since this is a return parameter type it is safe to unwrap. - let ret_param_ty = projection.skip_binder().term.ty().unwrap(); - let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); - debug!(?ret_param_ty); - let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys, ret_param_ty, diff --git a/tests/ui/async-await/expectation.rs b/tests/ui/async-await/expectation.rs new file mode 100644 index 0000000000000..72d6d2d6a3e22 --- /dev/null +++ b/tests/ui/async-await/expectation.rs @@ -0,0 +1,11 @@ +// check-pass +// edition: 2021 + +use std::fmt::Debug; +use std::future::Future; + +fn needs_future(_: impl Future>) {} + +fn main() { + needs_future(async { Box::new(()) }) +} diff --git a/tests/ui/impl-trait/issues/issue-78722.rs b/tests/ui/impl-trait/issues/issue-78722.rs index 7b5ab5f229835..88ec49a7e45cb 100644 --- a/tests/ui/impl-trait/issues/issue-78722.rs +++ b/tests/ui/impl-trait/issues/issue-78722.rs @@ -7,8 +7,8 @@ type F = impl core::future::Future; struct Bug { V1: [(); { fn concrete_use() -> F { - //~^ ERROR to be a future that resolves to `u8`, but it resolves to `()` async {} + //~^ ERROR mismatched types } let f: F = async { 1 }; //~^ ERROR `async` blocks are not allowed in constants diff --git a/tests/ui/impl-trait/issues/issue-78722.stderr b/tests/ui/impl-trait/issues/issue-78722.stderr index 05a2c135cf7c7..d135fec51ced8 100644 --- a/tests/ui/impl-trait/issues/issue-78722.stderr +++ b/tests/ui/impl-trait/issues/issue-78722.stderr @@ -7,13 +7,13 @@ LL | let f: F = async { 1 }; = note: see issue #85368 for more information = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable -error[E0271]: expected `[async block@$DIR/issue-78722.rs:11:13: 11:21]` to be a future that resolves to `u8`, but it resolves to `()` - --> $DIR/issue-78722.rs:9:30 +error[E0308]: mismatched types + --> $DIR/issue-78722.rs:10:19 | -LL | fn concrete_use() -> F { - | ^ expected `()`, found `u8` +LL | async {} + | ^^ expected `u8`, found `()` error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0658. -For more information about an error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr index b395c23ae0057..88382003a9a2d 100644 --- a/tests/ui/traits/new-solver/async.fail.stderr +++ b/tests/ui/traits/new-solver/async.fail.stderr @@ -1,17 +1,9 @@ -error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()` - --> $DIR/async.rs:12:17 +error[E0308]: mismatched types + --> $DIR/async.rs:12:23 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ expected `i32`, found `()` - | | - | required by a bound introduced by this call - | -note: required by a bound in `needs_async` - --> $DIR/async.rs:8:31 - | -LL | fn needs_async(_: impl Future) {} - | ^^^^^^^^^^^^ required by this bound in `needs_async` + | ^^ expected `i32`, found `()` error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs index 195cc35cad2ad..781d0c71d48be 100644 --- a/tests/ui/traits/new-solver/async.rs +++ b/tests/ui/traits/new-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()` + //[fail]~^ mismatched types } #[cfg(pass)]