Actually use the inferred ClosureKind from signature inference in coroutine-closures
This commit is contained in:
parent
385fa9d845
commit
3d9d5d7c96
@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
});
|
});
|
||||||
let closure_kind_ty = self.next_ty_var(TypeVariableOrigin {
|
|
||||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
let closure_kind_ty = match expected_kind {
|
||||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
Some(kind) => Ty::from_closure_kind(tcx, kind),
|
||||||
span: expr_span,
|
|
||||||
});
|
// Create a type variable (for now) to represent the closure kind.
|
||||||
|
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||||
|
None => self.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||||
|
span: expr_span,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin {
|
let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
|
let coroutine_kind_ty = match expected_kind {
|
||||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind),
|
||||||
span: expr_span,
|
|
||||||
});
|
// Create a type variable (for now) to represent the closure kind.
|
||||||
|
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||||
|
None => self.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||||
|
span: expr_span,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
|
let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
|
@ -399,16 +399,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Additionally, we can now constrain the coroutine's kind type.
|
// Additionally, we can now constrain the coroutine's kind type.
|
||||||
let ty::Coroutine(_, coroutine_args) =
|
//
|
||||||
*self.typeck_results.borrow().expr_ty(body.value).kind()
|
// We only do this if `infer_kind`, because if we have constrained
|
||||||
else {
|
// the kind from closure signature inference, the kind inferred
|
||||||
bug!();
|
// for the inner coroutine may actually be more restrictive.
|
||||||
};
|
if infer_kind {
|
||||||
self.demand_eqtype(
|
let ty::Coroutine(_, coroutine_args) =
|
||||||
span,
|
*self.typeck_results.borrow().expr_ty(body.value).kind()
|
||||||
coroutine_args.as_coroutine().kind_ty(),
|
else {
|
||||||
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
|
bug!();
|
||||||
);
|
};
|
||||||
|
self.demand_eqtype(
|
||||||
|
span,
|
||||||
|
coroutine_args.as_coroutine().kind_ty(),
|
||||||
|
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.log_closure_min_capture_info(closure_def_id, span);
|
self.log_closure_min_capture_info(closure_def_id, span);
|
||||||
|
@ -88,4 +88,38 @@ async fn async_main() {
|
|||||||
};
|
};
|
||||||
call_once(c).await;
|
call_once(c).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture something with `move`, but infer to `AsyncFnOnce`
|
||||||
|
{
|
||||||
|
let x = Hello(6);
|
||||||
|
let c = force_fnonce(async move || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
|
||||||
|
let x = &Hello(7);
|
||||||
|
let c = force_fnonce(async move || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture something by-ref, but infer to `AsyncFnOnce`
|
||||||
|
{
|
||||||
|
let x = Hello(8);
|
||||||
|
let c = force_fnonce(async || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
|
||||||
|
let x = &Hello(9);
|
||||||
|
let c = force_fnonce(async || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
31
src/tools/miri/tests/pass/async-closure-captures.stderr
Normal file
31
src/tools/miri/tests/pass/async-closure-captures.stderr
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error[E0597]: `x` does not live long enough
|
||||||
|
--> $DIR/async-closure-captures.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let c = force_fnonce(async move || {
|
||||||
|
| ____________________________________________-
|
||||||
|
LL | | println!("{x:?}");
|
||||||
|
| | ^ borrowed value does not live long enough
|
||||||
|
LL | | });
|
||||||
|
| | --
|
||||||
|
| | ||
|
||||||
|
| | |`x` dropped here while still borrowed
|
||||||
|
| |_________|borrow later used here
|
||||||
|
| value captured here by coroutine
|
||||||
|
|
||||||
|
error[E0597]: `x` does not live long enough
|
||||||
|
--> $DIR/async-closure-captures.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let c = force_fnonce(async move || {
|
||||||
|
| ____________________________________________-
|
||||||
|
LL | | println!("{x:?}");
|
||||||
|
| | ^ borrowed value does not live long enough
|
||||||
|
LL | | });
|
||||||
|
| | --
|
||||||
|
| | ||
|
||||||
|
| | |`x` dropped here while still borrowed
|
||||||
|
| |_________|borrow later used here
|
||||||
|
| value captured here by coroutine
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
@ -1,10 +0,0 @@
|
|||||||
Hello(0)
|
|
||||||
Hello(0)
|
|
||||||
Hello(1)
|
|
||||||
Hello(1)
|
|
||||||
Hello(2)
|
|
||||||
Hello(3)
|
|
||||||
Hello(3)
|
|
||||||
Hello(4)
|
|
||||||
Hello(4)
|
|
||||||
Hello(5)
|
|
@ -1,7 +1,7 @@
|
|||||||
//@ aux-build:block-on.rs
|
//@ aux-build:block-on.rs
|
||||||
//@ edition:2021
|
//@ edition:2021
|
||||||
//@ run-pass
|
|
||||||
//@ check-run-results
|
|
||||||
|
|
||||||
// Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
|
// Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
|
||||||
|
|
||||||
@ -79,4 +79,40 @@ async fn async_main() {
|
|||||||
};
|
};
|
||||||
call_once(c).await;
|
call_once(c).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture something with `move`, but infer to `AsyncFnOnce`
|
||||||
|
{
|
||||||
|
let x = Hello(6);
|
||||||
|
let c = force_fnonce(async move || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
|
||||||
|
let x = &Hello(7);
|
||||||
|
let c = force_fnonce(async move || {
|
||||||
|
println!("{x:?}");
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture something by-ref, but infer to `AsyncFnOnce`
|
||||||
|
{
|
||||||
|
let x = Hello(8);
|
||||||
|
let c = force_fnonce(async || {
|
||||||
|
println!("{x:?}");
|
||||||
|
//~^ ERROR `x` does not live long enough
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
|
||||||
|
let x = &Hello(9);
|
||||||
|
let c = force_fnonce(async || {
|
||||||
|
println!("{x:?}");
|
||||||
|
//~^ ERROR `x` does not live long enough
|
||||||
|
});
|
||||||
|
call_once(c).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
31
tests/ui/async-await/async-closures/captures.stderr
Normal file
31
tests/ui/async-await/async-closures/captures.stderr
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error[E0597]: `x` does not live long enough
|
||||||
|
--> $DIR/captures.rs:89:24
|
||||||
|
|
|
||||||
|
LL | let c = force_fnonce(async move || {
|
||||||
|
| ____________________________________________-
|
||||||
|
LL | | println!("{x:?}");
|
||||||
|
| | ^ borrowed value does not live long enough
|
||||||
|
LL | | });
|
||||||
|
| | --
|
||||||
|
| | ||
|
||||||
|
| | |`x` dropped here while still borrowed
|
||||||
|
| |_________|borrow later used here
|
||||||
|
| value captured here by coroutine
|
||||||
|
|
||||||
|
error[E0597]: `x` does not live long enough
|
||||||
|
--> $DIR/captures.rs:95:24
|
||||||
|
|
|
||||||
|
LL | let c = force_fnonce(async move || {
|
||||||
|
| ____________________________________________-
|
||||||
|
LL | | println!("{x:?}");
|
||||||
|
| | ^ borrowed value does not live long enough
|
||||||
|
LL | | });
|
||||||
|
| | --
|
||||||
|
| | ||
|
||||||
|
| | |`x` dropped here while still borrowed
|
||||||
|
| |_________|borrow later used here
|
||||||
|
| value captured here by coroutine
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
@ -2,18 +2,22 @@
|
|||||||
|
|
||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
|
|
||||||
fn main() {
|
fn needs_async_fn(_: impl async Fn()) {}
|
||||||
fn needs_async_fn(_: impl async Fn()) {}
|
|
||||||
|
|
||||||
|
fn a() {
|
||||||
let mut x = 1;
|
let mut x = 1;
|
||||||
needs_async_fn(async || {
|
needs_async_fn(async || {
|
||||||
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
|
//~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||||
x += 1;
|
x += 1;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
let x = String::new();
|
let x = String::new();
|
||||||
needs_async_fn(move || async move {
|
needs_async_fn(move || async move {
|
||||||
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
||||||
println!("{x}");
|
println!("{x}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
@ -1,26 +1,5 @@
|
|||||||
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
|
|
||||||
--> $DIR/wrong-fn-kind.rs:9:20
|
|
||||||
|
|
|
||||||
LL | needs_async_fn(async || {
|
|
||||||
| -------------- -^^^^^^^
|
|
||||||
| | |
|
|
||||||
| _____|______________this closure implements `async FnMut`, not `async Fn`
|
|
||||||
| | |
|
|
||||||
| | required by a bound introduced by this call
|
|
||||||
LL | |
|
|
||||||
LL | | x += 1;
|
|
||||||
| | - closure is `async FnMut` because it mutates the variable `x` here
|
|
||||||
LL | | });
|
|
||||||
| |_____- the requirement to implement `async Fn` derives from here
|
|
||||||
|
|
|
||||||
note: required by a bound in `needs_async_fn`
|
|
||||||
--> $DIR/wrong-fn-kind.rs:6:31
|
|
||||||
|
|
|
||||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
|
||||||
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
|
||||||
|
|
||||||
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
||||||
--> $DIR/wrong-fn-kind.rs:15:20
|
--> $DIR/wrong-fn-kind.rs:17:20
|
||||||
|
|
|
|
||||||
LL | needs_async_fn(move || async move {
|
LL | needs_async_fn(move || async move {
|
||||||
| -------------- -^^^^^^
|
| -------------- -^^^^^^
|
||||||
@ -35,11 +14,29 @@ LL | | });
|
|||||||
| |_____- the requirement to implement `async Fn` derives from here
|
| |_____- the requirement to implement `async Fn` derives from here
|
||||||
|
|
|
|
||||||
note: required by a bound in `needs_async_fn`
|
note: required by a bound in `needs_async_fn`
|
||||||
--> $DIR/wrong-fn-kind.rs:6:31
|
--> $DIR/wrong-fn-kind.rs:5:27
|
||||||
|
|
|
|
||||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||||
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
||||||
|
|
||||||
|
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||||
|
--> $DIR/wrong-fn-kind.rs:9:29
|
||||||
|
|
|
||||||
|
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||||
|
| --------------- change this to accept `FnMut` instead of `Fn`
|
||||||
|
...
|
||||||
|
LL | needs_async_fn(async || {
|
||||||
|
| _____--------------_--------_^
|
||||||
|
| | | |
|
||||||
|
| | | in this closure
|
||||||
|
| | expects `Fn` instead of `FnMut`
|
||||||
|
LL | |
|
||||||
|
LL | | x += 1;
|
||||||
|
| | - mutable borrow occurs due to use of `x` in closure
|
||||||
|
LL | | });
|
||||||
|
| |_____^ cannot borrow as mutable
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0525`.
|
Some errors have detailed explanations: E0525, E0596.
|
||||||
|
For more information about an error, try `rustc --explain E0525`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user