Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer async block return type from future expectation #109338

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
Expand All @@ -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<Repr>` 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,
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/async-await/expectation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// check-pass
// edition: 2021

use std::fmt::Debug;
use std::future::Future;

fn needs_future(_: impl Future<Output = Box<dyn Debug>>) {}

fn main() {
needs_future(async { Box::new(()) })
}
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/issues/issue-78722.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ type F = impl core::future::Future<Output = u8>;
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
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/impl-trait/issues/issue-78722.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ LL | let f: F = async { 1 };
= note: see issue #85368 <https://github.com/rust-lang/rust/issues/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`.
16 changes: 4 additions & 12 deletions tests/ui/traits/new-solver/async.fail.stderr
Original file line number Diff line number Diff line change
@@ -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<Output = i32>) {}
| ^^^^^^^^^^^^ 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`.
2 changes: 1 addition & 1 deletion tests/ui/traits/new-solver/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
#[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)]
Expand Down