bevyengine / bevyengine/bevy

`Option` and `Has` ignore sparse components in transmuted dense queries

Open
#16,397 2 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Bug D-Modest S-Ready-For-Implementation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version

[e155fe1d86](https://github.com/bevyengine/bevy/commit/e155fe1d86e3a21dd32832f2f1f6253593a4688f)

## What you did

Transmuted a `QueryState` to either `QueryState>` or `QueryState>`, where `S` is a sparse set component.

```rust
#[derive(Component)]
#[component(storage = "SparseSet")]
struct S;

let mut world = World::new();
world.spawn(S);

let mut query = world
.query::()
.transmute::<(Option<&S>, Has)>(&world);
let (option, has) = query.single(&world);

assert!(option.is_some());
assert!(has);
```

## What went wrong

The matched entity has an `S` component, but `Option<&S>` yields `None` and `Has` yields `false`.

## Additional information

`Option` and `Has` cache whether the component exists in `set_table` or `set_archetype`. To make this work for sparse set components, they set `IS_DENSE = false` and require sparse iteration. But `EntityMut` performs dense iteration, so the transmuted query is dense and calls `set_table`. `Option` and `Has` don't find the component in the table, since sparse set components are not stored in tables, and return `None` or `false` for the entire table.

#16396 would make this also occur in cases involving `FilteredEntityMut`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.