forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add detailed errors (bevyengine#2994)
# Objective - Improve error descriptions and help understand how to fix them - I noticed one today that could be expanded, it seemed like a good starting point ## Solution - Start something like https://github.com/rust-lang/rust/tree/master/compiler/rustc_error_codes/src/error_codes - Remove sentence about Rust mutability rules which is not very helpful in the error message I decided to start the error code with B for Bevy so that they're not confused with error code from rust (which starts with E) Longer term, there are a few more evolutions that can continue this: - the code samples should be compiled check, and even executed for some of them to check they have the correct error code in a panic - the error could be build on a page in the website like https://doc.rust-lang.org/error-index.html - most panic should have their own error code
- Loading branch information
Showing
6 changed files
with
155 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# B0001 | ||
|
||
To keep [Rust rules on references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references) (either one mutable reference or any number of immutable references) on a component, it is not possible to have two queries on the same component when one request mutable access to it in the same system. | ||
|
||
Erroneous code example: | ||
|
||
```rust,should_panic | ||
use bevy::prelude::*; | ||
#[derive(Component)] | ||
struct Player; | ||
#[derive(Component)] | ||
struct Enemy; | ||
fn move_enemies_to_player( | ||
mut enemies: Query<&mut Transform, With<Enemy>>, | ||
player: Query<&Transform, With<Player>>, | ||
) { | ||
// ... | ||
} | ||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_system(move_enemies_to_player) | ||
.run(); | ||
} | ||
``` | ||
|
||
This will panic, as it's not possible to have both a mutable and an immutable query on `Transform` at the same time. | ||
|
||
You have two solutions: | ||
|
||
Solution #1: use disjoint queries using [`Without`](https://docs.rs/bevy/*/bevy/ecs/query/struct.Without.html) | ||
|
||
As a `Player` entity won't be an `Enemy` at the same time, those two queries will acutally never target the same entity. This can be encoded in the query filter with [`Without`](https://docs.rs/bevy/*/bevy/ecs/query/struct.Without.html): | ||
|
||
```rust,no_run | ||
use bevy::prelude::*; | ||
#[derive(Component)] | ||
struct Player; | ||
#[derive(Component)] | ||
struct Enemy; | ||
fn move_enemies_to_player( | ||
mut enemies: Query<&mut Transform, With<Enemy>>, | ||
player: Query<&Transform, (With<Player>, Without<Enemy>)>, | ||
) { | ||
// ... | ||
} | ||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_system(move_enemies_to_player) | ||
.run(); | ||
} | ||
``` | ||
|
||
Solution #2: use a [`QuerySet`](https://docs.rs/bevy/*/bevy/ecs/system/struct.QuerySet.html) | ||
|
||
A [`QuerySet`](https://docs.rs/bevy/*/bevy/ecs/system/struct.QuerySet.html) will let you have conflicting queries as a parameter, but you will still be responsible of not using them at the same time in your system. | ||
|
||
```rust,no_run | ||
use bevy::prelude::*; | ||
#[derive(Component)] | ||
struct Player; | ||
#[derive(Component)] | ||
struct Enemy; | ||
fn move_enemies_to_player( | ||
mut transforms: QuerySet<( | ||
QueryState<&mut Transform, With<Enemy>>, | ||
QueryState<&Transform, With<Player>>, | ||
)>, | ||
) { | ||
// ... | ||
} | ||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_system(move_enemies_to_player) | ||
.run(); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# B0002 | ||
|
||
To keep [Rust rules on references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references) (either one mutable reference or any number of immutable references) on a resource, it is not possible to have more than one resource of a kind if one is mutable in the same system. This can happen between [`Res<T>`](https://docs.rs/bevy/*/bevy/ecs/system/struct.Res.html) and [`ResMut<T>`](https://docs.rs/bevy/*/bevy/ecs/system/struct.ResMut.html) for the same `T`, or between [`NonSend<T>`](https://docs.rs/bevy/*/bevy/ecs/system/struct.NonSend.html) and [`NonSendMut<T>`](https://docs.rs/bevy/*/bevy/ecs/system/struct.NonSendMut.html) for the same `T`. | ||
|
||
Erroneous code example: | ||
|
||
```rust,should_panic | ||
use bevy::prelude::*; | ||
fn update_materials( | ||
mut material_updater: ResMut<Assets<ColorMaterial>>, | ||
current_materials: Res<Assets<ColorMaterial>>, | ||
) { | ||
// ... | ||
} | ||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_system(update_materials) | ||
.run(); | ||
} | ||
``` | ||
|
||
This will panic, as it's not possible to have both a mutable and an immutable resource on `State` at the same time. | ||
|
||
As a mutable resource already provide access to the current resource value, you can remove the immutable resource. | ||
|
||
```rust,no_run | ||
use bevy::prelude::*; | ||
fn update_materials( | ||
mut material_updater: ResMut<Assets<ColorMaterial>>, | ||
) { | ||
// ... | ||
} | ||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_system(update_materials) | ||
.run(); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
name = "errors" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
bevy = { path = "../" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#[doc = include_str!("../B0001.md")] | ||
pub struct B0001; | ||
|
||
#[doc = include_str!("../B0002.md")] | ||
pub struct B0002; |