Skip to content

Commit

Permalink
Actually use the inferred ClosureKind from signature inference in cor…
Browse files Browse the repository at this point in the history
…outine-closures
  • Loading branch information
compiler-errors committed Apr 4, 2024
1 parent 385fa9d commit 3d9d5d7
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 60 deletions.
32 changes: 23 additions & 9 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let closure_kind_ty = self.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});

let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),

// 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 {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
Expand Down Expand Up @@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
);

let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let coroutine_kind_ty = match expected_kind {
Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind),

// 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 {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
Expand Down
26 changes: 16 additions & 10 deletions compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,16 +399,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);

// Additionally, we can now constrain the coroutine's kind type.
let ty::Coroutine(_, coroutine_args) =
*self.typeck_results.borrow().expr_ty(body.value).kind()
else {
bug!();
};
self.demand_eqtype(
span,
coroutine_args.as_coroutine().kind_ty(),
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
);
//
// We only do this if `infer_kind`, because if we have constrained
// the kind from closure signature inference, the kind inferred
// for the inner coroutine may actually be more restrictive.
if infer_kind {
let ty::Coroutine(_, coroutine_args) =
*self.typeck_results.borrow().expr_ty(body.value).kind()
else {
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);
Expand Down
34 changes: 34 additions & 0 deletions src/tools/miri/tests/pass/async-closure-captures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,38 @@ async fn async_main() {
};
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 changes: 31 additions & 0 deletions src/tools/miri/tests/pass/async-closure-captures.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 0 additions & 10 deletions src/tools/miri/tests/pass/async-closure-captures.stdout

This file was deleted.

40 changes: 38 additions & 2 deletions tests/ui/async-await/async-closures/captures.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@ aux-build:block-on.rs
//@ edition:2021
//@ run-pass
//@ check-run-results



// Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync

Expand Down Expand Up @@ -79,4 +79,40 @@ async fn async_main() {
};
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 changes: 31 additions & 0 deletions tests/ui/async-await/async-closures/captures.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 7 additions & 3 deletions tests/ui/async-await/async-closures/wrong-fn-kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

#![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;
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;
});
}

fn b() {
let x = String::new();
needs_async_fn(move || async move {
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
println!("{x}");
});
}

fn main() {}
49 changes: 23 additions & 26 deletions tests/ui/async-await/async-closures/wrong-fn-kind.stderr
Original file line number Diff line number Diff line change
@@ -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`
--> $DIR/wrong-fn-kind.rs:15:20
--> $DIR/wrong-fn-kind.rs:17:20
|
LL | needs_async_fn(move || async move {
| -------------- -^^^^^^
Expand All @@ -35,11 +14,29 @@ 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
--> $DIR/wrong-fn-kind.rs:5:27
|
LL | fn needs_async_fn(_: impl 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()) {}
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
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

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

0 comments on commit 3d9d5d7

Please sign in to comment.