Don't implement AsyncFn for FnDef/FnPtr that wouldnt implement Fn
This commit is contained in:
parent
9bad7ba324
commit
ec1c424293
@ -458,28 +458,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
|
||||
))
|
||||
}
|
||||
|
||||
ty::FnDef(..) | ty::FnPtr(..) => {
|
||||
let bound_sig = self_ty.fn_sig(cx);
|
||||
let sig = bound_sig.skip_binder();
|
||||
let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
|
||||
// `FnDef` and `FnPtr` only implement `AsyncFn*` when their
|
||||
// return type implements `Future`.
|
||||
let nested = vec![
|
||||
bound_sig
|
||||
.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()]))
|
||||
.upcast(cx),
|
||||
];
|
||||
let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
|
||||
let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
|
||||
output_coroutine_ty: sig.output(),
|
||||
coroutine_return_ty: future_output_ty,
|
||||
}),
|
||||
nested,
|
||||
))
|
||||
ty::FnDef(def_id, _) => {
|
||||
let sig = self_ty.fn_sig(cx);
|
||||
if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) {
|
||||
fn_item_to_async_callable(cx, sig)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
ty::FnPtr(..) => {
|
||||
let sig = self_ty.fn_sig(cx);
|
||||
if sig.skip_binder().is_fn_trait_compatible() {
|
||||
fn_item_to_async_callable(cx, sig)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Closure(_, args) => {
|
||||
let args = args.as_closure();
|
||||
let bound_sig = args.sig();
|
||||
@ -563,6 +558,29 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_item_to_async_callable<I: Interner>(
|
||||
cx: I,
|
||||
bound_sig: ty::Binder<I, ty::FnSig<I>>,
|
||||
) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
|
||||
let sig = bound_sig.skip_binder();
|
||||
let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
|
||||
// `FnDef` and `FnPtr` only implement `AsyncFn*` when their
|
||||
// return type implements `Future`.
|
||||
let nested = vec![
|
||||
bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx),
|
||||
];
|
||||
let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
|
||||
let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
|
||||
output_coroutine_ty: sig.output(),
|
||||
coroutine_return_ty: future_output_ty,
|
||||
}),
|
||||
nested,
|
||||
))
|
||||
}
|
||||
|
||||
/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
|
||||
/// that the closure's kind is compatible with the goal.
|
||||
fn coroutine_closure_to_certain_coroutine<I: Interner>(
|
||||
|
@ -467,8 +467,20 @@ fn assemble_async_closure_candidates(
|
||||
}
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
}
|
||||
ty::FnDef(..) | ty::FnPtr(..) => {
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
// Provide an impl, but only for suitable `fn` pointers.
|
||||
ty::FnPtr(sig) => {
|
||||
if sig.is_fn_trait_compatible() {
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
}
|
||||
}
|
||||
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
||||
ty::FnDef(def_id, _) => {
|
||||
let tcx = self.tcx();
|
||||
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
|
||||
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
{
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
//@ edition: 2021
|
||||
//@ only-x86_64
|
||||
|
||||
#![feature(async_closure, target_feature_11)]
|
||||
// `target_feature_11` just to test safe functions w/ target features.
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
#[target_feature(enable = "sse2")]
|
||||
fn target_feature() -> Pin<Box<dyn Future<Output = ()> + 'static>> { todo!() }
|
||||
|
||||
fn test(f: impl async Fn()) {}
|
||||
|
||||
fn main() {
|
||||
test(target_feature); //~ ERROR the trait bound
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn<()>` is not satisfied
|
||||
--> $DIR/fn-exception-target-features.rs:16:10
|
||||
|
|
||||
LL | test(target_feature);
|
||||
| ---- ^^^^^^^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/fn-exception-target-features.rs:13:17
|
||||
|
|
||||
LL | fn test(f: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `test`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
21
tests/ui/async-await/async-closures/fn-exception.rs
Normal file
21
tests/ui/async-await/async-closures/fn-exception.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//@ edition: 2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::future::Future;
|
||||
|
||||
unsafe extern "Rust" {
|
||||
pub unsafe fn unsafety() -> Pin<Box<dyn Future<Output = ()> + 'static>>;
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
pub safe fn abi() -> Pin<Box<dyn Future<Output = ()> + 'static>>;
|
||||
}
|
||||
|
||||
fn test(f: impl async Fn()) {}
|
||||
|
||||
fn main() {
|
||||
test(unsafety); //~ ERROR the trait bound
|
||||
test(abi); //~ ERROR the trait bound
|
||||
}
|
31
tests/ui/async-await/async-closures/fn-exception.stderr
Normal file
31
tests/ui/async-await/async-closures/fn-exception.stderr
Normal file
@ -0,0 +1,31 @@
|
||||
error[E0277]: the trait bound `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}: AsyncFn<()>` is not satisfied
|
||||
--> $DIR/fn-exception.rs:19:10
|
||||
|
|
||||
LL | test(unsafety);
|
||||
| ---- ^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/fn-exception.rs:16:17
|
||||
|
|
||||
LL | fn test(f: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `test`
|
||||
|
||||
error[E0277]: the trait bound `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}: AsyncFn<()>` is not satisfied
|
||||
--> $DIR/fn-exception.rs:20:10
|
||||
|
|
||||
LL | test(abi);
|
||||
| ---- ^^^ the trait `AsyncFn<()>` is not implemented for fn item `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/fn-exception.rs:16:17
|
||||
|
|
||||
LL | fn test(f: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `test`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user