Add some tests
This commit is contained in:
parent
881b6b5149
commit
37184e86ea
24 changed files with 402 additions and 9 deletions
|
@ -394,13 +394,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
coroutine_captures_by_ref_ty,
|
||||
);
|
||||
|
||||
let ty::Coroutine(_, args) = *self.typeck_results.borrow().expr_ty(body.value).kind()
|
||||
let ty::Coroutine(_, coroutine_args) =
|
||||
*self.typeck_results.borrow().expr_ty(body.value).kind()
|
||||
else {
|
||||
bug!();
|
||||
};
|
||||
self.demand_eqtype(
|
||||
span,
|
||||
args.as_coroutine().kind_ty(),
|
||||
coroutine_args.as_coroutine().kind_ty(),
|
||||
Ty::from_closure_kind(self.tcx, closure_kind),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -371,9 +371,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
if let Some(closure_kind) = obligation.self_ty().skip_binder().to_opt_closure_kind()
|
||||
&& let Some(goal_kind) =
|
||||
obligation.predicate.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
|
||||
let self_ty = obligation.self_ty().skip_binder();
|
||||
let target_kind_ty = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
|
||||
|
||||
// `to_opt_closure_kind` is kind of ICEy when it sees non-int types.
|
||||
if !(self_ty.is_integral() || self_ty.is_ty_var()) {
|
||||
return;
|
||||
}
|
||||
if !(target_kind_ty.is_integral() || self_ty.is_ty_var()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(closure_kind) = self_ty.to_opt_closure_kind()
|
||||
&& let Some(goal_kind) = target_kind_ty.to_opt_closure_kind()
|
||||
{
|
||||
if closure_kind.extends(goal_kind) {
|
||||
candidates.vec.push(AsyncFnKindHelperCandidate);
|
||||
|
|
15
tests/ui/async-await/async-closures/arg-mismatch.rs
Normal file
15
tests/ui/async-await/async-closures/arg-mismatch.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let c = async |x| {};
|
||||
c(1i32).await;
|
||||
c(2usize).await;
|
||||
//~^ ERROR mismatched types
|
||||
});
|
||||
}
|
21
tests/ui/async-await/async-closures/arg-mismatch.stderr
Normal file
21
tests/ui/async-await/async-closures/arg-mismatch.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/arg-mismatch.rs:12:11
|
||||
|
|
||||
LL | c(2usize).await;
|
||||
| - ^^^^^^ expected `i32`, found `usize`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: closure parameter defined here
|
||||
--> $DIR/arg-mismatch.rs:10:24
|
||||
|
|
||||
LL | let c = async |x| {};
|
||||
| ^
|
||||
help: change the type of the numeric literal from `usize` to `i32`
|
||||
|
|
||||
LL | c(2i32).await;
|
||||
| ~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,23 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// run-pass
|
||||
|
||||
// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this.
|
||||
// ignore-pass (test emits codegen-time warnings)
|
||||
|
||||
#![feature(async_closure, async_fn_traits)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
use std::ops::AsyncFnOnce;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let x = async || {};
|
||||
|
||||
async fn needs_async_fn_once(x: impl AsyncFnOnce()) {
|
||||
x().await;
|
||||
}
|
||||
needs_async_fn_once(x).await;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>, found std::pin::Pin<&ReErased mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()])>.See <https://github.com/rust-lang/rust/issues/114858>.
|
||||
WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type: expected *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i8, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]), found *mut Coroutine(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), [i32, std::future::ResumeTy, (), (), CoroutineWitness(DefId(0:8 ~ async_fn_once_for_async_fn[6cdf]::main::{closure#0}::{closure#1}), []), ()]).See <https://github.com/rust-lang/rust/issues/114858>.
|
20
tests/ui/async-await/async-closures/auxiliary/block-on.rs
Normal file
20
tests/ui/async-await/async-closures/auxiliary/block-on.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
// edition: 2021
|
||||
|
||||
#![feature(async_closure, noop_waker, async_fn_traits)]
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::pin;
|
||||
use std::task::*;
|
||||
|
||||
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
|
||||
let mut fut = pin!(fut);
|
||||
// Poll loop, just to test the future...
|
||||
let ctx = &mut Context::from_waker(Waker::noop());
|
||||
|
||||
loop {
|
||||
match unsafe { fut.as_mut().poll(ctx) } {
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(t) => break t,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// run-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let x = async |x: &str| -> String { x.to_owned() };
|
||||
let mut s = x("hello, world").await;
|
||||
s.truncate(4);
|
||||
println!("{s}");
|
||||
});
|
||||
}
|
26
tests/ui/async-await/async-closures/brand.rs
Normal file
26
tests/ui/async-await/async-closures/brand.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// build-pass
|
||||
|
||||
#![feature(async_closure, async_fn_traits)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::AsyncFn;
|
||||
|
||||
struct S;
|
||||
struct B<'b>(PhantomData<&'b mut &'b mut ()>);
|
||||
|
||||
impl S {
|
||||
async fn q<F: AsyncFn(B<'_>)>(self, f: F) {
|
||||
f(B(PhantomData)).await;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
S.q(async |b: B<'_>| { println!("...") }).await;
|
||||
});
|
||||
}
|
18
tests/ui/async-await/async-closures/higher-ranked-return.rs
Normal file
18
tests/ui/async-await/async-closures/higher-ranked-return.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
|
||||
// known-bug: unknown
|
||||
// Borrow checking doesn't like that higher-ranked output...
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let x = async move |x: &str| -> &str {
|
||||
x
|
||||
};
|
||||
let s = x("hello!").await;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/higher-ranked-return.rs:13:46
|
||||
|
|
||||
LL | let x = async move |x: &str| -> &str {
|
||||
| ________________________________-________----_^
|
||||
| | | |
|
||||
| | | return type of async closure `{async closure body@$DIR/higher-ranked-return.rs:13:46: 15:10}` contains a lifetime `'2`
|
||||
| | let's call the lifetime of this reference `'1`
|
||||
LL | | x
|
||||
LL | | };
|
||||
| |_________^ returning this value requires that `'1` must outlive `'2`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -1,10 +1,16 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// check-pass
|
||||
// build-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
let x = async move |x: &str| {
|
||||
println!("{x}");
|
||||
};
|
||||
block_on::block_on(async {
|
||||
let x = async move |x: &str| {
|
||||
println!("{x}");
|
||||
};
|
||||
x("hello!").await;
|
||||
});
|
||||
}
|
||||
|
|
12
tests/ui/async-await/async-closures/is-not-fn.rs
Normal file
12
tests/ui/async-await/async-closures/is-not-fn.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// edition:2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
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.
|
||||
}
|
19
tests/ui/async-await/async-closures/is-not-fn.stderr
Normal file
19
tests/ui/async-await/async-closures/is-not-fn.stderr
Normal file
|
@ -0,0 +1,19 @@
|
|||
error[E0277]: expected a `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
|
||||
--> $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}`
|
||||
| |
|
||||
| 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: required by a bound in `needs_fn`
|
||||
--> $DIR/is-not-fn.rs:6:25
|
||||
|
|
||||
LL | fn needs_fn(x: impl FnOnce()) {}
|
||||
| ^^^^^^^^ required by this bound in `needs_fn`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -0,0 +1,20 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
struct NoCopy;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let s = NoCopy;
|
||||
let x = async move || {
|
||||
drop(s);
|
||||
};
|
||||
x().await;
|
||||
x().await;
|
||||
//~^ ERROR use of moved value: `x`
|
||||
});
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/move-consuming-capture.rs:17:9
|
||||
|
|
||||
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
|
||||
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
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
21
tests/ui/async-await/async-closures/move-is-async-fn.rs
Normal file
21
tests/ui/async-await/async-closures/move-is-async-fn.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// build-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let s = String::from("hello, world");
|
||||
let c = async move || {
|
||||
println!("{s}");
|
||||
};
|
||||
c().await;
|
||||
c().await;
|
||||
|
||||
fn is_static<T: 'static>(_: T) {}
|
||||
is_static(c);
|
||||
});
|
||||
}
|
19
tests/ui/async-await/async-closures/mutate.rs
Normal file
19
tests/ui/async-await/async-closures/mutate.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
// run-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let mut prefix = String::from("Hello");
|
||||
let mut c = async move |x: &str| {
|
||||
prefix.push(',');
|
||||
println!("{prefix} {x}!")
|
||||
};
|
||||
c("world").await;
|
||||
c("rust").await;
|
||||
});
|
||||
}
|
21
tests/ui/async-await/async-closures/not-lending.rs
Normal file
21
tests/ui/async-await/async-closures/not-lending.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
// Make sure that we can't make an async closure that evaluates to a self-borrow.
|
||||
// i.e. that the generator may reference captures, but the future's return type can't.
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let s = String::new();
|
||||
let x = async move || -> &String { &s };
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
|
||||
let s = String::new();
|
||||
let x = async move || { &s };
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
});
|
||||
}
|
24
tests/ui/async-await/async-closures/not-lending.stderr
Normal file
24
tests/ui/async-await/async-closures/not-lending.stderr
Normal file
|
@ -0,0 +1,24 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/not-lending.rs:14:42
|
||||
|
|
||||
LL | let x = async move || -> &String { &s };
|
||||
| ------------------------ ^^^^^^ returning this value requires that `'1` must outlive `'2`
|
||||
| | |
|
||||
| | return type of async closure `{async closure body@$DIR/not-lending.rs:14:42: 14:48}` contains a lifetime `'2`
|
||||
| lifetime `'1` represents this closure's body
|
||||
|
|
||||
= note: closure implements `Fn`, so references to captured variables can't escape the closure
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/not-lending.rs:18:31
|
||||
|
|
||||
LL | let x = async move || { &s };
|
||||
| ------------- ^^^^^^ returning this value requires that `'1` must outlive `'2`
|
||||
| | |
|
||||
| | return type of async closure `{async closure body@$DIR/not-lending.rs:18:31: 18:37}` contains a lifetime `'2`
|
||||
| lifetime `'1` represents this closure's body
|
||||
|
|
||||
= note: closure implements `Fn`, so references to captured variables can't escape the closure
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
14
tests/ui/async-await/async-closures/return-type-mismatch.rs
Normal file
14
tests/ui/async-await/async-closures/return-type-mismatch.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// aux-build:block-on.rs
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
fn main() {
|
||||
block_on::block_on(async {
|
||||
let x = async || -> i32 { 0 };
|
||||
let y: usize = x().await;
|
||||
//~^ ERROR mismatched types
|
||||
});
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/return-type-mismatch.rs:11:24
|
||||
|
|
||||
LL | let y: usize = x().await;
|
||||
| ^^^^^^^^^ expected `usize`, found `i32`
|
||||
|
|
||||
help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit
|
||||
|
|
||||
LL | let y: usize = x().await.try_into().unwrap();
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
18
tests/ui/async-await/async-closures/wrong-fn-kind.rs
Normal file
18
tests/ui/async-await/async-closures/wrong-fn-kind.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// edition:2021
|
||||
|
||||
// FIXME(async_closures): This needs a better error message!
|
||||
|
||||
#![feature(async_closure, async_fn_traits)]
|
||||
|
||||
use std::ops::AsyncFn;
|
||||
|
||||
fn main() {
|
||||
fn needs_async_fn(_: impl AsyncFn()) {}
|
||||
|
||||
let mut x = 1;
|
||||
needs_async_fn(async || {
|
||||
//~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>
|
||||
// FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth.
|
||||
x += 1;
|
||||
});
|
||||
}
|
22
tests/ui/async-await/async-closures/wrong-fn-kind.stderr
Normal file
22
tests/ui/async-await/async-closures/wrong-fn-kind.stderr
Normal file
|
@ -0,0 +1,22 @@
|
|||
error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not satisfied
|
||||
--> $DIR/wrong-fn-kind.rs:13:20
|
||||
|
|
||||
LL | needs_async_fn(async || {
|
||||
| _____--------------_^
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
LL | |
|
||||
LL | | // FIXME: Should say "closure is AsyncFnMut but it needs AsyncFn" or sth.
|
||||
LL | | x += 1;
|
||||
LL | | });
|
||||
| |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not implemented for `i16`
|
||||
|
|
||||
note: required by a bound in `needs_async_fn`
|
||||
--> $DIR/wrong-fn-kind.rs:10:31
|
||||
|
|
||||
LL | fn needs_async_fn(_: impl AsyncFn()) {}
|
||||
| ^^^^^^^^^ required by this bound in `needs_async_fn`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Reference in a new issue