Skip to content

Commit

Permalink
Rework try_overloaded_call_traits to not prefer taking async closure …
Browse files Browse the repository at this point in the history
…by move
  • Loading branch information
compiler-errors committed Feb 6, 2024
1 parent 20c24c3 commit e988944
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 24 deletions.
18 changes: 11 additions & 7 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::TypeInference,
span: callee_expr.span,
});
// We may actually receive a coroutine back whose kind is different
// from the closure that this dispatched from. This is because when
// we have no captures, we automatically implement `FnOnce`. This
// impl forces the closure kind to `FnOnce` i.e. `u8`.
let kind_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: callee_expr.span,
});
let call_sig = self.tcx.mk_fn_sig(
[coroutine_closure_sig.tupled_inputs_ty],
coroutine_closure_sig.to_coroutine(
self.tcx,
closure_args.parent_args(),
// Inherit the kind ty of the closure, since we're calling this
// coroutine with the most relaxed `AsyncFn*` trait that we can.
// We don't necessarily need to do this here, but it saves us
// computing one more infer var that will get constrained later.
closure_args.kind_ty(),
kind_ty,
self.tcx.coroutine_for_closure(def_id),
tupled_upvars_ty,
),
Expand Down Expand Up @@ -263,14 +267,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Try the options that are least restrictive on the caller first.
for (opt_trait_def_id, method_name, borrow) in [
(self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
(self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
(self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
(self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true),
(self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
(
self.tcx.lang_items().async_fn_mut_trait(),
Ident::with_dummy_span(sym::async_call_mut),
true,
),
(self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
(
self.tcx.lang_items().async_fn_once_trait(),
Ident::with_dummy_span(sym::async_call_once),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_const = self.tcx().is_const_fn_raw(def_id);
match self.infcx.closure_kind(self_ty) {
Some(closure_kind) => {
let no_borrows = self
let no_borrows = match self
.infcx
.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty())
.tuple_fields()
.is_empty();
.kind()
{
ty::Tuple(tys) => tys.is_empty(),
ty::Error(_) => false,
_ => bug!("tuple_fields called on non-tuple"),
};
if no_borrows && closure_kind.extends(kind) {
candidates.vec.push(ClosureCandidate { is_const });
} else if kind == ty::ClosureKind::FnOnce {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/async-await/async-closures/def-path.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ LL | let x = async || {};
| -- the expected `async` closure body
LL |
LL | let () = x();
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t witness=?6t}`
| |
| expected `async` closure body, found `()`
|
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t witness=?6t}`
found unit type `()`

error: aborting due to 1 previous error
Expand Down
5 changes: 1 addition & 4 deletions tests/ui/async-await/async-closures/is-not-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,5 @@
fn main() {
fn needs_fn(x: impl FnOnce()) {}
needs_fn(async || {});
//~^ ERROR expected a `FnOnce()` closure, found `{coroutine-closure@
// FIXME(async_closures): This should explain in more detail how async fns don't
// implement the regular `Fn` traits. Or maybe we should just fix it and make them
// when there are no upvars or whatever.
//~^ ERROR expected `{coroutine-closure@is-not-fn.rs:7:14}` to be a closure that returns `()`
}
10 changes: 5 additions & 5 deletions tests/ui/async-await/async-closures/is-not-fn.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0277]: expected a `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
error[E0271]: expected `{coroutine-closure@is-not-fn.rs:7:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:7:23: 7:25}`
--> $DIR/is-not-fn.rs:7:14
|
LL | needs_fn(async || {});
| -------- ^^^^^^^^^^^ expected an `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
| -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
| |
| required by a bound introduced by this call
|
= help: the trait `FnOnce<()>` is not implemented for `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
= note: wrap the `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` in a closure with no arguments: `|| { /* code */ }`
= note: expected unit type `()`
found `async` closure body `{async closure body@$DIR/is-not-fn.rs:7:23: 7:25}`
note: required by a bound in `needs_fn`
--> $DIR/is-not-fn.rs:6:25
|
Expand All @@ -16,4 +16,4 @@ LL | fn needs_fn(x: impl FnOnce()) {}

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0271`.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ LL | let x = async move || {
| - move occurs because `x` has type `{coroutine-closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait
...
LL | x().await;
| --- `x` moved due to this method call
| --- `x` moved due to this call
LL | x().await;
| ^ value used here after move
|
note: `async_call_once` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
note: this value implements `FnOnce`, which causes it to be moved when called
--> $DIR/move-consuming-capture.rs:16:9
|
LL | x().await;
| ^

error: aborting due to 1 previous error

Expand Down
24 changes: 24 additions & 0 deletions tests/ui/async-await/async-fn/dyn-pos.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
Expand All @@ -19,6 +22,10 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
std::boxed::Box<F, A>

error[E0038]: the trait `AsyncFn` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
Expand All @@ -30,6 +37,9 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
Expand All @@ -42,6 +52,10 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFn` cannot be made into an object
Expand All @@ -54,6 +68,9 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
Expand All @@ -66,6 +83,10 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFn` cannot be made into an object
Expand All @@ -81,6 +102,9 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
::: $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>

error: aborting due to 7 previous errors

Expand Down

0 comments on commit e988944

Please sign in to comment.