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`:
c00957a3e2/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
This commit is contained in:
commit
44c7a2dbff
4 changed files with 70 additions and 20 deletions
|
@ -401,6 +401,45 @@ impl<'tcx> CoroutineClosureArgs<'tcx> {
|
|||
pub fn coroutine_witness_ty(self) -> Ty<'tcx> {
|
||||
self.split().coroutine_witness_ty
|
||||
}
|
||||
|
||||
pub fn has_self_borrows(&self) -> bool {
|
||||
match self.coroutine_captures_by_ref_ty().kind() {
|
||||
ty::FnPtr(sig) => sig
|
||||
.skip_binder()
|
||||
.visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST })
|
||||
.is_break(),
|
||||
ty::Error(_) => true,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will
|
||||
/// detect only regions bound *at* the debruijn index.
|
||||
struct HasRegionsBoundAt {
|
||||
binder: ty::DebruijnIndex,
|
||||
}
|
||||
// FIXME: Could be optimized to not walk into components with no escaping bound vars.
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRegionsBoundAt {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
self.binder.shift_in(1);
|
||||
t.super_visit_with(self)?;
|
||||
self.binder.shift_out(1);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
if let ty::ReBound(binder, _) = *r
|
||||
&& self.binder == binder
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue