Skip to content

Allow write access in NestedQuery - #25642

Open
tim-blackbird wants to merge 1 commit into
bevyengine:mainfrom
tim-blackbird:push-oxqlqltrnqzl
Open

tim-blackbird wants to merge 1 commit into
bevyengine:mainfrom
tim-blackbird:push-oxqlqltrnqzl

Conversation

@tim-blackbird

@tim-blackbird tim-blackbird commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Objective

Remove the ReadOnlyQueryData bound on D for NestedQuery<D, F>

Solution

As far as I could tell the only remaining issue here is the need to store the the same QueryState for both QueryData and QueryData::ReadOnly, but that same bound allows us to soundly transmute between the State of D and D::ReadOnly as much as we want.

Hopefully I'm right about that, kinda awkward otherwise

Notes For Reviewers

  • I've dug into bevy_ecs guts before but I'm not great with unsafe code generally so this needs a good look. This change could be totally wrong :) (also it's past 2:00 AM. help)
  • See 5067e4b for a temp relationship QueryData impl yoinked from Nested Queries #21557's description for testing these changes.
  • I also removed the ReadOnlyQueryData bound for QueryState::as_transmuted_state. I don't think that's an issue?
  • The safety doc for as_transmuted_state isn't quite precise enough. In this PR I effectively do the exact opposite of what it says is safe. I use to_readonly to get D::ReadOnly and then use as_transmuted_state to get back to D. I feel it should reference the D and F the state was created with instead of the D and F it currently has?
  • The QueryState::to_readonly impl is kinda funny, hihi

Testing

Mirrored the existing NestedQuery tests to check that the mutable access within NestedQuery correctly conflicts with other accesses.
In 5067e4b there are some tests including one that mutably accesses a component through the inner NestedQuery.
This simple test passes miri at least.

Hi! :3

@tim-blackbird tim-blackbird added A-ECS Entities, components, systems, and events D-Unsafe Touches with unsafe code in some way S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 2, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in ECS Sep 2, 2026
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible D-Complex Quite challenging from either a design or technical perspective. Ask for help! X-Uncontroversial This work is generally agreed upon labels Sep 2, 2026
@chescock

chescock commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Oh! Hah, I was just about to create a PR with a different approach to this when I saw this one had been opened :).

... Ah, okay, you're storing QueryState<D::ReadOnly, F> so that the types match. That's what I tried at first, and I believe it is sound, but it's really hard to prove that in the safety comments. As you note, you're doing the opposite of what the safety comment in as_transmuted_state says :).

Let me go open my PR with the other approach for comparison. ... okay, #25652! And now I'm going to go copy the unit tests from this PR, since I didn't think to write any.

chescock pushed a commit to chescock/bevy that referenced this pull request Sep 2, 2026

@chescock chescock left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, I'm happy to go with this approach if we want! I do think it works, but we'll probably want to adjust the safety comments a bit to make it clear that it works.

@@ -148,14 +179,30 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// `NewD` must have a subset of the access that `D` does and match the exact same archetypes/tables

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This safety requirement will need to be changed if we take this approach, since it's not satisfied by the calls in NestedQuery.

}

fn init_state(world: &mut World) -> Self::State {
// SAFETY: `WorldQuery::init_nested_access` calls `QueryState::init_access`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be changed somehow, too, but I couldn't figure out what to write here.

We need to show that we call QueryState<D, F>::init_access and not QueryState<D::ReadOnly, F>::init_access, and we might need to modify the safety requirements on new_unchecked, since it doesn't currently allow that sort of shenanigans.

Or maybe I was overthinking it and this is just fine, since the transmutes are obviously opposites of each other?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your thought process here sums up why I feel your implementation is better :)
This transmute hokey pokey does feel "simply" correct considering the constraints, but it's messy and hard to pin down exactly

// If `D::IS_ARCHETYPAL == false` or `F::IS_ARCHETYPAL == false`,
// then the nested query may filter out some entities that *it* matches,
// but it will never filter the outer query.
impl<D: ReadOnlyQueryData, F: QueryFilter> ArchetypeQueryData for NestedQuery<D, F> {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bound should be loosened, too.

Suggested change
impl<D: QueryData, F: QueryFilter> ArchetypeQueryData for NestedQuery<D, F> {}

Hmm, GitHub is being weird about suggestions on lines you didn't change.

@tim-blackbird

Copy link
Copy Markdown
Contributor Author

I'm inclined to close this in favor of #25652

@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in ECS Sep 15, 2026
@alice-i-cecile alice-i-cecile added S-Adopt-Me The original PR author has no intent to complete this work. Pick me up! and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 16, 2026
@github-project-automation github-project-automation Bot moved this from Done to Needs SME Triage in ECS Sep 16, 2026
@Zeophlite Zeophlite added the S-Merge-Conflicts Merge conflicts :( Add this label on top of other S- labels. label Sep 19, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Complex Quite challenging from either a design or technical perspective. Ask for help! D-Unsafe Touches with unsafe code in some way S-Adopt-Me The original PR author has no intent to complete this work. Pick me up! S-Merge-Conflicts Merge conflicts :( Add this label on top of other S- labels. X-Uncontroversial This work is generally agreed upon

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

5 participants