Add some tests

This commit is contained in:
Michael Goulet 2024-01-25 17:43:35 +00:00
parent 881b6b5149
commit 37184e86ea
24 changed files with 402 additions and 9 deletions

View file

@ -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),
);
}

View file

@ -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);

View 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
});
}

View 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`.

View file

@ -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;
});
}

View file

@ -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>.

View 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,
}
}
}

View file

@ -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}");
});
}

View 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;
});
}

View 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;
});
}

View file

@ -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

View file

@ -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;
});
}

View 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.
}

View 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`.

View file

@ -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`
});
}

View file

@ -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`.

View 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);
});
}

View 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;
});
}

View 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
});
}

View 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

View 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
});
}

View file

@ -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`.

View 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;
});
}

View 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`.