diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2024-05-22 19:04:45 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-22 19:04:45 +0200 |
| commit | 44c7a2dbffef822bd8df3f154b37bf1bc51b1d9c (patch) | |
| tree | 902ae271c5d39bd50f4fdaf3aa91962c6430b7d7 /compiler/rustc_trait_selection/src/solve | |
| parent | 5b485f04dedef5d9eb69224c21d83f984017fc66 (diff) | |
| parent | 2e97dae8d468623474d05dd84c270583ec3ed374 (diff) | |
| download | rust-44c7a2dbffef822bd8df3f154b37bf1bc51b1d9c.tar.gz rust-44c7a2dbffef822bd8df3f154b37bf1bc51b1d9c.zip | |
Rollup merge of #125259 - compiler-errors:fn-mut-as-a-treat, r=oli-obk
An async closure may implement `FnMut`/`Fn` if it has no self-borrows
There's no reason that async closures may not implement `FnMut` or `Fn` if they don't actually borrow anything with the closure's env lifetime. Specifically, #123660 made it so that we don't always need to borrow captures from the closure's env.
See the doc comment on `should_reborrow_from_env_of_parent_coroutine_closure`:
https://github.com/rust-lang/rust/blob/c00957a3e269219413041a4e3565f33b1f9d0779/compiler/rustc_hir_typeck/src/upvar.rs#L1777-L1823
If there are no such borrows, then we are free to implement `FnMut` and `Fn` as permitted by our closure's inferred `ClosureKind`.
As far as I can tell, this change makes `async || {}` work in precisely the set of places they used to work before #120361.
Fixes #125247.
r? oli-obk
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve')
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs | 13 |
1 files changed, 5 insertions, 8 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 930ae5af811..6f68875e6f6 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -300,14 +300,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( return Err(NoSolution); } - // If `Fn`/`FnMut`, we only implement this goal if we - // have no captures. - let no_borrows = match args.tupled_upvars_ty().kind() { - ty::Tuple(tys) => tys.is_empty(), - ty::Error(_) => false, - _ => bug!("tuple_fields called on non-tuple"), - }; - if closure_kind != ty::ClosureKind::FnOnce && !no_borrows { + // A coroutine-closure implements `FnOnce` *always*, since it may + // always be called once. It additionally implements `Fn`/`FnMut` + // only if it has no upvars referencing the closure-env lifetime, + // and if the closure kind permits it. + if closure_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() { return Err(NoSolution); } |
