diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.rs b/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.rs index 462e9dbf1f..d3cdb06078 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.rs +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.rs @@ -1,24 +1,46 @@ use bevy_ecs::prelude::*; -use bevy_ecs::system::SystemState; +use bevy_ecs::system::{QueryLens, SystemState}; #[derive(Component, Eq, PartialEq, Debug)] struct Foo(u32); +#[derive(Component, Eq, PartialEq, Debug)] +struct Bar(u32); + fn main() { let mut world = World::default(); - let e = world.spawn(Foo(10_u32)).id(); + let e = world.spawn((Foo(10_u32), Bar(10_u32))).id(); - let mut system_state = SystemState::>::new(&mut world); + let mut system_state = SystemState::<(Query<&mut Foo>, Query<&mut Bar>)>::new(&mut world); { - let mut query = system_state.get_mut(&mut world); - let mut lens = query.as_query_lens(); + let (mut foo_query, mut bar_query) = system_state.get_mut(&mut world); dbg!("hi"); { + let mut lens = foo_query.as_query_lens(); let mut data: Mut = lens.query().get_inner(e).unwrap(); let mut data2: Mut = lens.query().get_inner(e).unwrap(); //~^ E0499 assert_eq!(&mut *data, &mut *data2); // oops UB } + + { + let mut join: QueryLens<(&mut Foo, &mut Bar)> = foo_query.join(&mut bar_query); + let mut query = join.query(); + let (_, mut data) = query.single_mut().unwrap(); + let mut data2 = bar_query.single_mut().unwrap(); + //~^ E0499 + assert_eq!(&mut *data, &mut *data2); // oops UB + } + + { + let mut join: QueryLens<(&mut Foo, &mut Bar)> = + foo_query.join_inner(bar_query.reborrow()); + let mut query = join.query(); + let (_, mut data) = query.single_mut().unwrap(); + let mut data2 = bar_query.single_mut().unwrap(); + //~^ E0499 + assert_eq!(&mut *data, &mut *data2); // oops UB + } dbg!("bye"); } } diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.stderr b/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.stderr index 170a83d012..70aa6b37f6 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.stderr +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_lens_lifetime_safety.stderr @@ -1,14 +1,38 @@ error[E0499]: cannot borrow `lens` as mutable more than once at a time - --> tests/ui/query_lens_lifetime_safety.rs:18:39 + --> tests/ui/query_lens_lifetime_safety.rs:21:39 | -17 | let mut data: Mut = lens.query().get_inner(e).unwrap(); +20 | let mut data: Mut = lens.query().get_inner(e).unwrap(); | ---- first mutable borrow occurs here -18 | let mut data2: Mut = lens.query().get_inner(e).unwrap(); +21 | let mut data2: Mut = lens.query().get_inner(e).unwrap(); | ^^^^ second mutable borrow occurs here -19 | -20 | assert_eq!(&mut *data, &mut *data2); // oops UB +22 | +23 | assert_eq!(&mut *data, &mut *data2); // oops UB | ---- first borrow later used here -error: aborting due to 1 previous error +error[E0499]: cannot borrow `bar_query` as mutable more than once at a time + --> tests/ui/query_lens_lifetime_safety.rs:30:29 + | +27 | let mut join: QueryLens<(&mut Foo, &mut Bar)> = foo_query.join(&mut bar_query); + | -------------- first mutable borrow occurs here +... +30 | let mut data2 = bar_query.single_mut().unwrap(); + | ^^^^^^^^^ second mutable borrow occurs here +31 | +32 | assert_eq!(&mut *data, &mut *data2); // oops UB + | ---- first borrow later used here + +error[E0499]: cannot borrow `bar_query` as mutable more than once at a time + --> tests/ui/query_lens_lifetime_safety.rs:40:29 + | +37 | foo_query.join_inner(bar_query.reborrow()); + | --------- first mutable borrow occurs here +... +40 | let mut data2 = bar_query.single_mut().unwrap(); + | ^^^^^^^^^ second mutable borrow occurs here +41 | +42 | assert_eq!(&mut *data, &mut *data2); // oops UB + | ---- first borrow later used here + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0499`. diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index d732dd54ac..cc97433b76 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2234,10 +2234,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// Like `transmute_lens` the query terms can be changed with some restrictions. /// See [`Self::transmute_lens`] for more details. - pub fn join( - &mut self, - other: &mut Query, - ) -> QueryLens<'_, NewD> { + pub fn join<'a, OtherD: QueryData, NewD: QueryData>( + &'a mut self, + other: &'a mut Query, + ) -> QueryLens<'a, NewD> { self.join_filtered(other) } @@ -2263,7 +2263,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// - [`join`](Self::join) to join using a mutable borrow of the [`Query`]. pub fn join_inner( self, - other: &mut Query, + other: Query<'w, '_, OtherD>, ) -> QueryLens<'w, NewD> { self.join_filtered_inner(other) } @@ -2276,15 +2276,16 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// terms like `Added` and `Changed` will only be respected if they are in /// the type signature. pub fn join_filtered< + 'a, OtherD: QueryData, OtherF: QueryFilter, NewD: QueryData, NewF: QueryFilter, >( - &mut self, - other: &mut Query, - ) -> QueryLens<'_, NewD, NewF> { - self.reborrow().join_filtered_inner(other) + &'a mut self, + other: &'a mut Query, + ) -> QueryLens<'a, NewD, NewF> { + self.reborrow().join_filtered_inner(other.reborrow()) } /// Equivalent to [`Self::join_inner`] but also includes a [`QueryFilter`] type. @@ -2306,7 +2307,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { NewF: QueryFilter, >( self, - other: &mut Query, + other: Query<'w, '_, OtherD, OtherF>, ) -> QueryLens<'w, NewD, NewF> { let state = self .state