Skip to content

Commit d0e294c

Browse files
committed
Query filter types must be ReadOnlyWorldQuery (#6008)
# Objective Fixes Issue #6005. ## Solution Replaced WorldQuery with ReadOnlyWorldQuery on F generic in Query filters and QueryState to restrict its trait bound. ## Migration Guide Query filter (`F`) generics are now bound by `ReadOnlyWorldQuery`, rather than `WorldQuery`. If for some reason you were requesting `Query<&A, &mut B>`, please use `Query<&A, With<B>>` instead.
1 parent 1f0fa59 commit d0e294c

File tree

10 files changed

+51
-42
lines changed

10 files changed

+51
-42
lines changed

crates/bevy_ecs/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ mod tests {
5757
bundle::Bundle,
5858
component::{Component, ComponentId},
5959
entity::Entity,
60-
query::{Added, ChangeTrackers, Changed, FilteredAccess, With, Without, WorldQuery},
60+
query::{
61+
Added, ChangeTrackers, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without,
62+
},
6163
system::Resource,
6264
world::{Mut, World},
6365
};
@@ -902,7 +904,7 @@ mod tests {
902904
}
903905
}
904906

905-
fn get_filtered<F: WorldQuery>(world: &mut World) -> Vec<Entity> {
907+
fn get_filtered<F: ReadOnlyWorldQuery>(world: &mut World) -> Vec<Entity> {
906908
world
907909
.query_filtered::<Entity, F>()
908910
.iter(world)

crates/bevy_ecs/src/query/iter.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ use super::{QueryFetch, QueryItem, ReadOnlyWorldQuery};
1313
///
1414
/// This struct is created by the [`Query::iter`](crate::system::Query::iter) and
1515
/// [`Query::iter_mut`](crate::system::Query::iter_mut) methods.
16-
pub struct QueryIter<'w, 's, Q: WorldQuery, F: WorldQuery> {
16+
pub struct QueryIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
1717
tables: &'w Tables,
1818
archetypes: &'w Archetypes,
1919
query_state: &'s QueryState<Q, F>,
2020
cursor: QueryIterationCursor<'w, 's, Q, F>,
2121
}
2222

23-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIter<'w, 's, Q, F> {
23+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
2424
/// # Safety
2525
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
2626
/// have unique access to the components they query.
@@ -41,7 +41,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIter<'w, 's, Q, F> {
4141
}
4242
}
4343

44-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F> {
44+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Iterator for QueryIter<'w, 's, Q, F> {
4545
type Item = QueryItem<'w, Q>;
4646

4747
#[inline(always)]
@@ -70,12 +70,12 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F>
7070
}
7171

7272
// This is correct as [`QueryIter`] always returns `None` once exhausted.
73-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> FusedIterator for QueryIter<'w, 's, Q, F> {}
73+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> FusedIterator for QueryIter<'w, 's, Q, F> {}
7474

7575
/// An [`Iterator`] over [`Query`](crate::system::Query) results of a list of [`Entity`]s.
7676
///
7777
/// This struct is created by the [`Query::iter_many`](crate::system::Query::iter_many) and [`Query::iter_many_mut`](crate::system::Query::iter_many_mut) methods.
78-
pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator>
78+
pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, I: Iterator>
7979
where
8080
I::Item: Borrow<Entity>,
8181
{
@@ -88,7 +88,7 @@ where
8888
query_state: &'s QueryState<Q, F>,
8989
}
9090

91-
impl<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
91+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
9292
where
9393
I::Item: Borrow<Entity>,
9494
{
@@ -267,14 +267,16 @@ where
267267
/// [`Query`]: crate::system::Query
268268
/// [`Query::iter_combinations`]: crate::system::Query::iter_combinations
269269
/// [`Query::iter_combinations_mut`]: crate::system::Query::iter_combinations_mut
270-
pub struct QueryCombinationIter<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> {
270+
pub struct QueryCombinationIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize> {
271271
tables: &'w Tables,
272272
archetypes: &'w Archetypes,
273273
query_state: &'s QueryState<Q, F>,
274274
cursors: [QueryIterationCursor<'w, 's, Q, F>; K],
275275
}
276276

277-
impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<'w, 's, Q, F, K> {
277+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
278+
QueryCombinationIter<'w, 's, Q, F, K>
279+
{
278280
/// # Safety
279281
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
280282
/// have unique access to the components they query.
@@ -436,7 +438,7 @@ where
436438
}
437439
}
438440

439-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> ExactSizeIterator for QueryIter<'w, 's, Q, F>
441+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> ExactSizeIterator for QueryIter<'w, 's, Q, F>
440442
where
441443
F: ArchetypeFilter,
442444
{
@@ -473,7 +475,7 @@ where
473475
{
474476
}
475477

476-
struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: WorldQuery> {
478+
struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
477479
table_id_iter: std::slice::Iter<'s, TableId>,
478480
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
479481
fetch: QueryFetch<'w, Q>,
@@ -485,7 +487,7 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: WorldQuery> {
485487
phantom: PhantomData<Q>,
486488
}
487489

488-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Clone for QueryIterationCursor<'w, 's, Q, F>
490+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Clone for QueryIterationCursor<'w, 's, Q, F>
489491
where
490492
QueryFetch<'w, Q>: Clone,
491493
QueryFetch<'w, F>: Clone,
@@ -503,7 +505,7 @@ where
503505
}
504506
}
505507

506-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
508+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's, Q, F> {
507509
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
508510

509511
unsafe fn init_empty(

crates/bevy_ecs/src/query/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) unsafe fn debug_checked_unreachable() -> ! {
1919

2020
#[cfg(test)]
2121
mod tests {
22-
use super::WorldQuery;
22+
use super::{ReadOnlyWorldQuery, WorldQuery};
2323
use crate::prelude::{AnyOf, Entity, Or, QueryState, With, Without};
2424
use crate::query::{ArchetypeFilter, QueryCombinationIter, QueryFetch};
2525
use crate::system::{IntoSystem, Query, System, SystemState};
@@ -68,7 +68,7 @@ mod tests {
6868
fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize)
6969
where
7070
Q: WorldQuery,
71-
F: WorldQuery,
71+
F: ReadOnlyWorldQuery,
7272
F::ReadOnly: ArchetypeFilter,
7373
for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
7474
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,
@@ -81,7 +81,7 @@ mod tests {
8181
fn assert_all_sizes_equal<Q, F>(world: &mut World, expected_size: usize)
8282
where
8383
Q: WorldQuery,
84-
F: WorldQuery,
84+
F: ReadOnlyWorldQuery,
8585
F::ReadOnly: ArchetypeFilter,
8686
for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
8787
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,

crates/bevy_ecs/src/query/state.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ use bevy_utils::tracing::Instrument;
1313
use fixedbitset::FixedBitSet;
1414
use std::{borrow::Borrow, fmt};
1515

16-
use super::{NopWorldQuery, QueryItem, QueryManyIter, ROQueryItem};
16+
use super::{NopWorldQuery, QueryItem, QueryManyIter, ROQueryItem, ReadOnlyWorldQuery};
1717

1818
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
1919
#[repr(C)]
2020
// SAFETY NOTE:
2121
// Do not add any new fields that use the `Q` or `F` generic parameters as this may
2222
// make `QueryState::as_transmuted_state` unsound if not done with care.
23-
pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()> {
23+
pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
2424
world_id: WorldId,
2525
pub(crate) archetype_generation: ArchetypeGeneration,
2626
pub(crate) matched_tables: FixedBitSet,
@@ -35,13 +35,13 @@ pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()> {
3535
pub(crate) filter_state: F::State,
3636
}
3737

38-
impl<Q: WorldQuery, F: WorldQuery> FromWorld for QueryState<Q, F> {
38+
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> FromWorld for QueryState<Q, F> {
3939
fn from_world(world: &mut World) -> Self {
4040
world.query_filtered()
4141
}
4242
}
4343

44-
impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
44+
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
4545
/// Converts this `QueryState` reference to a `QueryState` that does not access anything mutably.
4646
pub fn as_readonly(&self) -> &QueryState<Q::ReadOnly, F::ReadOnly> {
4747
// SAFETY: invariant on `WorldQuery` trait upholds that `Q::ReadOnly` and `F::ReadOnly`
@@ -71,15 +71,15 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
7171
/// `NewF` must have a subset of the access that `F` does and match the exact same archetypes/tables
7272
pub(crate) unsafe fn as_transmuted_state<
7373
NewQ: WorldQuery<State = Q::State>,
74-
NewF: WorldQuery<State = F::State>,
74+
NewF: ReadOnlyWorldQuery<State = F::State>,
7575
>(
7676
&self,
7777
) -> &QueryState<NewQ, NewF> {
7878
&*(self as *const QueryState<Q, F> as *const QueryState<NewQ, NewF>)
7979
}
8080
}
8181

82-
impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
82+
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
8383
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
8484
pub fn new(world: &mut World) -> Self {
8585
let fetch_state = Q::init_state(world);

crates/bevy_ecs/src/system/query.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,14 +273,14 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug};
273273
/// [`Table`]: crate::storage::Table
274274
/// [`With`]: crate::query::With
275275
/// [`Without`]: crate::query::Without
276-
pub struct Query<'world, 'state, Q: WorldQuery, F: WorldQuery = ()> {
276+
pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
277277
pub(crate) world: &'world World,
278278
pub(crate) state: &'state QueryState<Q, F>,
279279
pub(crate) last_change_tick: u32,
280280
pub(crate) change_tick: u32,
281281
}
282282

283-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
283+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
284284
/// Creates a new query.
285285
///
286286
/// # Safety
@@ -1380,7 +1380,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
13801380
}
13811381
}
13821382

1383-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w Query<'_, 's, Q, F> {
1383+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> IntoIterator for &'w Query<'_, 's, Q, F> {
13841384
type Item = ROQueryItem<'w, Q>;
13851385
type IntoIter = QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly>;
13861386

@@ -1389,7 +1389,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w Query<'_, 's, Q,
13891389
}
13901390
}
13911391

1392-
impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w mut Query<'_, 's, Q, F> {
1392+
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> IntoIterator for &'w mut Query<'_, 's, Q, F> {
13931393
type Item = QueryItem<'w, Q>;
13941394
type IntoIter = QueryIter<'w, 's, Q, F>;
13951395

@@ -1434,7 +1434,7 @@ impl std::fmt::Display for QueryComponentError {
14341434
}
14351435
}
14361436

1437-
impl<'w, 's, Q: ReadOnlyWorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
1437+
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
14381438
/// Returns the query item for the given [`Entity`], with the actual "inner" world lifetime.
14391439
///
14401440
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,21 @@ pub trait SystemParamFetch<'world, 'state>: SystemParamState {
135135
) -> Self::Item;
136136
}
137137

138-
impl<'w, 's, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParam for Query<'w, 's, Q, F> {
138+
impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParam
139+
for Query<'w, 's, Q, F>
140+
{
139141
type Fetch = QueryState<Q, F>;
140142
}
141143

142144
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
143-
unsafe impl<Q: ReadOnlyWorldQuery, F: WorldQuery> ReadOnlySystemParamFetch for QueryState<Q, F> {}
145+
unsafe impl<Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> ReadOnlySystemParamFetch
146+
for QueryState<Q, F>
147+
{
148+
}
144149

145150
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
146151
// this QueryState conflicts with any prior access, a panic will occur.
147-
unsafe impl<Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamState
152+
unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParamState
148153
for QueryState<Q, F>
149154
{
150155
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
@@ -174,7 +179,7 @@ unsafe impl<Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamState
174179
}
175180
}
176181

177-
impl<'w, 's, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'w, 's>
182+
impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParamFetch<'w, 's>
178183
for QueryState<Q, F>
179184
{
180185
type Item = Query<'w, 's, Q, F>;
@@ -1595,7 +1600,7 @@ mod tests {
15951600
use super::SystemParam;
15961601
use crate::{
15971602
self as bevy_ecs, // Necessary for the `SystemParam` Derive when used inside `bevy_ecs`.
1598-
query::WorldQuery,
1603+
query::{ReadOnlyWorldQuery, WorldQuery},
15991604
system::Query,
16001605
};
16011606

@@ -1605,7 +1610,7 @@ mod tests {
16051610
'w,
16061611
's,
16071612
Q: WorldQuery + Send + Sync + 'static,
1608-
F: WorldQuery + Send + Sync + 'static = (),
1613+
F: ReadOnlyWorldQuery + Send + Sync + 'static = (),
16091614
> {
16101615
_query: Query<'w, 's, Q, F>,
16111616
}

crates/bevy_ecs/src/world/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
StorageType,
1717
},
1818
entity::{AllocAtWithoutReplacement, Entities, Entity},
19-
query::{QueryState, WorldQuery},
19+
query::{QueryState, ReadOnlyWorldQuery, WorldQuery},
2020
storage::{Column, SparseSet, Storages},
2121
system::Resource,
2222
};
@@ -610,7 +610,7 @@ impl World {
610610
/// assert_eq!(matching_entities, vec![e2]);
611611
/// ```
612612
#[inline]
613-
pub fn query_filtered<Q: WorldQuery, F: WorldQuery>(&mut self) -> QueryState<Q, F> {
613+
pub fn query_filtered<Q: WorldQuery, F: ReadOnlyWorldQuery>(&mut self) -> QueryState<Q, F> {
614614
QueryState::new(self)
615615
}
616616

crates/bevy_reflect/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub mod __macro_exports {
9393
}
9494

9595
#[cfg(test)]
96-
#[allow(clippy::blacklisted_name, clippy::approx_constant)]
96+
#[allow(clippy::disallowed_types, clippy::approx_constant)]
9797
mod tests {
9898
#[cfg(feature = "glam")]
9999
use ::glam::{vec3, Vec3};
@@ -188,7 +188,7 @@ mod tests {
188188
}
189189

190190
#[test]
191-
#[allow(clippy::blacklisted_name)]
191+
#[allow(clippy::disallowed_types)]
192192
fn reflect_unit_struct() {
193193
#[derive(Reflect)]
194194
struct Foo(u32, u64);

crates/bevy_tasks/src/task_pool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl TaskPool {
150150
// before this function returns. However, rust has no way of knowing
151151
// this so we must convert to 'static here to appease the compiler as it is unable to
152152
// validate safety.
153-
let executor: &async_executor::Executor = &*self.executor;
153+
let executor: &async_executor::Executor = &self.executor;
154154
let executor: &'scope async_executor::Executor = unsafe { mem::transmute(executor) };
155155
let local_executor: &'scope async_executor::LocalExecutor =
156156
unsafe { mem::transmute(local_executor) };
@@ -287,7 +287,7 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> {
287287
}
288288

289289
#[cfg(test)]
290-
#[allow(clippy::blacklisted_name)]
290+
#[allow(clippy::disallowed_types)]
291291
mod tests {
292292
use super::*;
293293
use std::sync::{

crates/bevy_ui/src/flex/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{CalculatedSize, Node, Style, UiScale};
44
use bevy_ecs::{
55
entity::Entity,
66
event::EventReader,
7-
query::{Changed, With, Without, WorldQuery},
7+
query::{Changed, ReadOnlyWorldQuery, With, Without},
88
system::{Query, RemovedComponents, Res, ResMut, Resource},
99
};
1010
use bevy_hierarchy::{Children, Parent};
@@ -234,7 +234,7 @@ pub fn flex_node_system(
234234
update_changed(&mut *flex_surface, scale_factor, node_query);
235235
}
236236

237-
fn update_changed<F: WorldQuery>(
237+
fn update_changed<F: ReadOnlyWorldQuery>(
238238
flex_surface: &mut FlexSurface,
239239
scaling_factor: f64,
240240
query: Query<(Entity, &Style, Option<&CalculatedSize>), F>,

0 commit comments

Comments
 (0)