mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Improve upvar analysis for deref of child capture
This commit is contained in:
parent
ecade534c6
commit
ae4a4794e7
@ -1862,8 +1862,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
///
|
///
|
||||||
/// (1.) Are we borrowing data owned by the parent closure? We can determine if
|
/// (1.) Are we borrowing data owned by the parent closure? We can determine if
|
||||||
/// that is the case by checking if the parent capture is by move, EXCEPT if we
|
/// that is the case by checking if the parent capture is by move, EXCEPT if we
|
||||||
/// apply a deref projection, which means we're reborrowing a reference that we
|
/// apply a deref projection of an immutable reference, reborrows of immutable
|
||||||
/// captured by move.
|
/// references which aren't restricted to the LUB of the lifetimes of the deref
|
||||||
|
/// chain. This is why `&'short mut &'long T` can be reborrowed as `&'long T`.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let x = &1i32; // Let's call this lifetime `'1`.
|
/// let x = &1i32; // Let's call this lifetime `'1`.
|
||||||
@ -1902,10 +1903,22 @@ fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
// (1.)
|
// (1.)
|
||||||
(!parent_capture.is_by_ref()
|
(!parent_capture.is_by_ref()
|
||||||
&& !matches!(
|
// This is just inlined `place.deref_tys()` but truncated to just
|
||||||
child_capture.place.projections.get(parent_capture.place.projections.len()),
|
// the child projections. Namely, look for a `&T` deref, since we
|
||||||
Some(Projection { kind: ProjectionKind::Deref, .. })
|
// can always extend `&'short mut &'long T` to `&'long T`.
|
||||||
))
|
&& !child_capture
|
||||||
|
.place
|
||||||
|
.projections
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.skip(parent_capture.place.projections.len())
|
||||||
|
.any(|(idx, proj)| {
|
||||||
|
matches!(proj.kind, ProjectionKind::Deref)
|
||||||
|
&& matches!(
|
||||||
|
child_capture.place.ty_before_projection(idx).kind(),
|
||||||
|
ty::Ref(.., ty::Mutability::Not)
|
||||||
|
)
|
||||||
|
}))
|
||||||
// (2.)
|
// (2.)
|
||||||
|| matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::Mutable))
|
|| matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::Mutable))
|
||||||
}
|
}
|
||||||
|
46
tests/ui/async-await/async-closures/imm-deref-lending.rs
Normal file
46
tests/ui/async-await/async-closures/imm-deref-lending.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//@ edition: 2021
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
|
|
||||||
|
struct FooS {
|
||||||
|
precise: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_inside_mut(f: &mut &FooS) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_inside_ref(f: &&mut FooS) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_ref_inside_mut(f: &mut &mut FooS) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_inside_box(f: Box<&FooS>) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_inside_ref(f: &Box<FooS>) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_inside_box(f: Box<Box<FooS>>) {
|
||||||
|
let x: impl AsyncFn() = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
49
tests/ui/async-await/async-closures/imm-deref-not-lending.rs
Normal file
49
tests/ui/async-await/async-closures/imm-deref-not-lending.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
|
|
||||||
|
struct FooS {
|
||||||
|
precise: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_inside_mut(f: &mut &FooS) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_inside_ref(f: &&mut FooS) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected to fail, no immutable reference here.
|
||||||
|
fn mut_ref_inside_mut(f: &mut &mut FooS) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
//~^ ERROR async closure does not implement `Fn`
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_inside_box(f: Box<&FooS>) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_inside_ref(f: &Box<FooS>) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected to fail, no immutable reference here.
|
||||||
|
fn box_inside_box(f: Box<Box<FooS>>) {
|
||||||
|
let x: impl Fn() -> _ = async move || {
|
||||||
|
//~^ ERROR async closure does not implement `Fn`
|
||||||
|
let y = &f.precise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,14 @@
|
|||||||
|
error: async closure does not implement `Fn` because it captures state from its environment
|
||||||
|
--> $DIR/imm-deref-not-lending.rs:23:29
|
||||||
|
|
|
||||||
|
LL | let x: impl Fn() -> _ = async move || {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: async closure does not implement `Fn` because it captures state from its environment
|
||||||
|
--> $DIR/imm-deref-not-lending.rs:43:29
|
||||||
|
|
|
||||||
|
LL | let x: impl Fn() -> _ = async move || {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user