Skip to content

Commit 7456253

Browse files
Infer async block return type from future expectation
1 parent ab9bb3e commit 7456253

File tree

6 files changed

+47
-26
lines changed

6 files changed

+47
-26
lines changed

Diff for: compiler/rustc_hir_typeck/src/closure.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
293293
let gen_trait = tcx.lang_items().gen_trait();
294294
let is_gen = gen_trait == Some(trait_def_id);
295295

296-
if !is_fn && !is_gen {
296+
let future_trait = tcx.lang_items().future_trait();
297+
let is_future = future_trait == Some(trait_def_id);
298+
299+
if !(is_fn || is_gen || is_future) {
297300
debug!("not fn or generator");
298301
return None;
299302
}
@@ -305,6 +308,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
305308
return None;
306309
}
307310

311+
// Since this is a return parameter type it is safe to unwrap.
312+
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
313+
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
314+
debug!(?ret_param_ty);
315+
308316
let input_tys = if is_fn {
309317
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
310318
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
@@ -314,17 +322,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
314322
&ty::Tuple(tys) => tys,
315323
_ => return None,
316324
}
325+
} else if is_future {
326+
// HACK: Skip infer vars to `ui/generic-associated-types/issue-89008.rs` pass.
327+
// Otherwise, we end up with inferring the closure signature to be
328+
// `fn() -> Empty<Repr>` instead of `fn() -> Self::LineStream<'a, Repr>` and
329+
// opaque type inference gets bungled. Similarly, skip opaques, because we don't
330+
// replace them with infer vars, and opaque type inference gets bungled in
331+
// `async fn ..() -> impl Trait {}` cases.
332+
if ret_param_ty.is_ty_var() || ret_param_ty.has_opaque_types() {
333+
return None;
334+
}
335+
336+
let resume_ty_def_id = self.tcx.require_lang_item(hir::LangItem::ResumeTy, cause_span);
337+
self.tcx.mk_type_list(&[self
338+
.tcx
339+
.mk_adt(self.tcx.adt_def(resume_ty_def_id), ty::List::empty())])
317340
} else {
318341
// Generators with a `()` resume type may be defined with 0 or 1 explicit arguments,
319342
// else they must have exactly 1 argument. For now though, just give up in this case.
320343
return None;
321344
};
322345

323-
// Since this is a return parameter type it is safe to unwrap.
324-
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
325-
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
326-
debug!(?ret_param_ty);
327-
328346
let sig = projection.rebind(self.tcx.mk_fn_sig(
329347
input_tys,
330348
ret_param_ty,

Diff for: tests/ui/async-await/expectation.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// check-pass
2+
// edition: 2021
3+
4+
use std::fmt::Debug;
5+
use std::future::Future;
6+
7+
fn needs_future(_: impl Future<Output = Box<dyn Debug>>) {}
8+
9+
fn main() {
10+
needs_future(async { Box::new(()) })
11+
}

Diff for: tests/ui/impl-trait/issues/issue-78722.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ type F = impl core::future::Future<Output = u8>;
77
struct Bug {
88
V1: [(); {
99
fn concrete_use() -> F {
10-
//~^ ERROR to be a future that resolves to `u8`, but it resolves to `()`
1110
async {}
11+
//~^ ERROR mismatched types
1212
}
1313
let f: F = async { 1 };
1414
//~^ ERROR `async` blocks are not allowed in constants

Diff for: tests/ui/impl-trait/issues/issue-78722.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ LL | let f: F = async { 1 };
77
= note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information
88
= help: add `#![feature(const_async_blocks)]` to the crate attributes to enable
99

10-
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 `()`
11-
--> $DIR/issue-78722.rs:9:30
10+
error[E0308]: mismatched types
11+
--> $DIR/issue-78722.rs:10:19
1212
|
13-
LL | fn concrete_use() -> F {
14-
| ^ expected `()`, found `u8`
13+
LL | async {}
14+
| ^^ expected `u8`, found `()`
1515

1616
error: aborting due to 2 previous errors
1717

18-
Some errors have detailed explanations: E0271, E0658.
19-
For more information about an error, try `rustc --explain E0271`.
18+
Some errors have detailed explanations: E0308, E0658.
19+
For more information about an error, try `rustc --explain E0308`.

Diff for: tests/ui/traits/new-solver/async.fail.stderr

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
1-
error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()`
2-
--> $DIR/async.rs:12:17
1+
error[E0308]: mismatched types
2+
--> $DIR/async.rs:12:23
33
|
44
LL | needs_async(async {});
5-
| ----------- ^^^^^^^^ expected `i32`, found `()`
6-
| |
7-
| required by a bound introduced by this call
8-
|
9-
note: required by a bound in `needs_async`
10-
--> $DIR/async.rs:8:31
11-
|
12-
LL | fn needs_async(_: impl Future<Output = i32>) {}
13-
| ^^^^^^^^^^^^ required by this bound in `needs_async`
5+
| ^^ expected `i32`, found `()`
146

157
error: aborting due to previous error
168

17-
For more information about this error, try `rustc --explain E0271`.
9+
For more information about this error, try `rustc --explain E0308`.

Diff for: tests/ui/traits/new-solver/async.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
1010
#[cfg(fail)]
1111
fn main() {
1212
needs_async(async {});
13-
//[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()`
13+
//[fail]~^ mismatched types
1414
}
1515

1616
#[cfg(pass)]

0 commit comments

Comments
 (0)