Switch to ui_test in compile fail tests. (#12810)

# Objective

Make compile fail tests less likely to break with new Rust versions.
Closes #12627

## Solution

Switch from [`trybuild`](https://github.com/dtolnay/trybuild) to
[`ui_test`](https://github.com/oli-obk/ui_test).

## TODO

- [x] Update `bevy_ecs_compile_fail_tests`
- [x] Update `bevy_macros_compile_fail_tests`
- [x] Update `bevy_reflect_compile_fail_tests`

---------

Co-authored-by: Oli Scherer <github35764891676564198441@oli-obk.de>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
This commit is contained in:
Brezak 2024-04-27 02:00:57 +02:00 committed by GitHub
parent de9dc9c204
commit 9d59e52bb0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
107 changed files with 896 additions and 427 deletions

View file

@ -52,5 +52,5 @@ jobs:
base: "main" base: "main"
title: "Preparing Next Release" title: "Preparing Next Release"
body: | body: |
Preparing next release Preparing next release. This PR has been auto-generated.
This PR has been auto-generated UI tests have not been automatically bumped to the latest version, please fix them manually.

View file

@ -19,6 +19,7 @@ exclude = [
"crates/bevy_ecs_compile_fail_tests", "crates/bevy_ecs_compile_fail_tests",
"crates/bevy_macros_compile_fail_tests", "crates/bevy_macros_compile_fail_tests",
"crates/bevy_reflect_compile_fail_tests", "crates/bevy_reflect_compile_fail_tests",
"crates/bevy_compile_test_utils",
] ]
members = [ members = [
"crates/*", "crates/*",

View file

@ -0,0 +1,15 @@
[package]
name = "bevy_compile_test_utils"
edition = "2021"
description = "Utils for compile tests used in the engine"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
publish = false
[dependencies]
ui_test = "0.22.3"
[[test]]
name = "example"
harness = false

View file

@ -0,0 +1,44 @@
# Helpers for compile fail tests
This crate contains everything needed to set up compile tests for the Bevy repo. It, like all Bevy compile test crates, is excluded from the Bevy workspace. This is done to not fail [`crater` tests](https://github.com/rust-lang/crater) for Bevy. The `CI` workflow executes these tests on the stable rust toolchain see ([tools/ci](../../tools/ci/src/main.rs)).
## Writing new test cases
Test cases are annotated .rs files. These annotations define how the test case should be run and what we're expecting to fail. Please see <https://github.com/oli-obk/ui_test/blob/main/README.md> for more information.
Annotations can roughly be split into global annotations which are prefixed with `//@` and define how tests should be run and error annotations which are prefixed with `//~` and define where errors we expect to happen. From the global annotations, you're only likely to care about `//@check-pass` which will make any compile errors in the test trigger a test failure.
The error annotations are composed of two parts.
An optional location specifier:
- `^` The error happens on the line above.
- `v` The error happens on the line below.
- `|` The error annotation is connected to another one.
- If the location specifier is missing, the error is assumed to happen on the same line as the annotation.
An error matcher:
- `E####` The error we're expecting has the [`####` rustc error code](https://doc.rust-lang.org/error_codes/error-index.html), e.g `E0499`
- `<lint_name>` The given [compiler lint](https://doc.rust-lang.org/rustc/lints/index.html) is triggered, e.g. `dead_code`
- `LEVEL: <substring>` A compiler error of the given level (valid levels are: `ERROR`, `HELP`, `WARN` or `NOTE`) will be raised and it will contain the `substring`. Substrings can contain spaces.
- `LEVEL: /<regex>/` Same as above but a regex is used to match the error message.
An example of an error annotation would be `//~v ERROR: missing trait`. This error annotation will match any error occurring on the line below that contains the substring `missing trait`.
## Adding compile fail tests for a crate that doesn't have them
This will be a rather involved process. You'll have to:
- Create an empty library crate in the [`crates`](..) directory.
- Add this crate as a `dev-dependency`.
- Create a folder called `tests` within the new crate.
- Add a test runner file to this folder. The file should contain a main function calling one of the test functions defined in this crate.
- Add a `[[test]]` table to the `Cargo.toml`. This table will need to contain `harness = false` and `name = <name of the test runner file you defined>`.
- Modify the [`Ci`](../../tools/ci/) tool to run `cargo test` on this crate.
- And finally, write your compile tests.
If you have any questions, don't be scared to ask for help.
## A note about `.stderr` files
We're capable of generating `.stderr` files for all our compile tests. These files contain the error output generated by the test. To create or regenerate them yourself, trigger the tests with the `BLESS` environment variable set to any value (e.g. `BLESS="some symbolic value"`). We currently have to ignore mismatches between these files and the actual stderr output from their corresponding test due to issues with file paths. We attempt to sanitize file paths but for proc-macros, the compiler error messages contain file paths to the current toolchain's copy of the standard library. If we knew of a way to construct a path to the current toolchains folder we could fix this.

View file

@ -0,0 +1,101 @@
use std::{
env,
path::{Path, PathBuf},
};
// Re-export ui_test so all the tests use the same version.
pub use ui_test;
use ui_test::{
default_file_filter, default_per_file_config, run_tests_generic,
status_emitter::{Gha, StatusEmitter, Text},
Args, Config, OutputConflictHandling,
};
/// Use this instead of hand rolling configs.
///
/// `root_dir` is the directory your tests are contained in. Needs to be a path from crate root.
fn basic_config(root_dir: impl Into<PathBuf>, args: &Args) -> Config {
let mut config = Config {
dependencies_crate_manifest_path: Some("Cargo.toml".into()),
bless_command: Some("`cargo test` with the BLESS environment variable set to any non empty value".to_string()),
output_conflict_handling: if env::var_os("BLESS").is_some() {
OutputConflictHandling::Bless
} else {
// stderr output changes between rust versions so we just rely on annotations
OutputConflictHandling::Ignore
},
..Config::rustc(root_dir)
};
config.with_args(args);
let bevy_root = "..";
// Don't leak contributor filesystem paths
config.path_stderr_filter(Path::new(bevy_root), b"$BEVY_ROOT");
config.path_stderr_filter(Path::new(env!("RUSTUP_HOME")), b"$RUSTUP_HOME");
// ui_test doesn't compile regex with perl character classes.
// \pL = unicode class for letters, \pN = unicode class for numbers
config.stderr_filter(r"\/home\/[\pL\pN_@#\-\. ]+", "$HOME");
// Paths in .stderr seem to always be normalized to use /. Handle both anyway.
config.stderr_filter(
r"[a-zA-Z]:(?:\\|\/)users(?:\\|\/)[\pL\pN_@#\-\. ]+", // NOTE: [\pL\pN_@#\-\. ] is a poor attempt at handling usernames
"$HOME",
);
config
}
/// Runs ui tests for a single directory.
///
/// `root_dir` is the directory your tests are contained in. Needs to be a path from crate root.
pub fn test(test_root: impl Into<PathBuf>) -> ui_test::Result<()> {
test_multiple([test_root])
}
/// Run ui tests with the given config
pub fn test_with_config(config: Config) -> ui_test::Result<()> {
test_with_multiple_configs([config])
}
/// Runs ui tests for a multiple directories.
///
/// `root_dirs` paths need to come from crate root.
pub fn test_multiple(
test_roots: impl IntoIterator<Item = impl Into<PathBuf>>,
) -> ui_test::Result<()> {
let args = Args::test()?;
let configs = test_roots.into_iter().map(|root| basic_config(root, &args));
test_with_multiple_configs(configs)
}
/// Run ui test with the given configs.
///
/// Tests for configs are run in parallel.
pub fn test_with_multiple_configs(
configs: impl IntoIterator<Item = Config>,
) -> ui_test::Result<()> {
let configs = configs.into_iter().collect();
let emitter: Box<dyn StatusEmitter + Send> = if env::var_os("CI").is_some() {
Box::new((
Text::verbose(),
Gha::<true> {
name: env!("CARGO_PKG_NAME").to_string(),
},
))
} else {
Box::new(Text::quiet())
};
run_tests_generic(
configs,
default_file_filter,
default_per_file_config,
emitter,
)
}

View file

@ -0,0 +1,10 @@
fn main() -> bevy_compile_test_utils::ui_test::Result<()> {
// Run all tests in the tests/example_tests folder.
// If we had more tests we could either call this function
// on everysingle one or use test_multiple and past it an array
// of paths.
//
// Don't forget that when running tests the working directory
// is set to the crate root.
bevy_compile_test_utils::test("tests/example_tests")
}

View file

@ -0,0 +1,24 @@
// Compiler warnings also need to be annotated. We don't
// want to annotate all the unused variables so let's instruct
// the compiler to ignore them.
#![allow(unused_variables)]
fn bad_moves() {
let x = String::new();
// Help diagnostics need to be annotated
let y = x;
//~^ HELP: consider cloning
// We expect a failure on this line
println!("{x}"); //~ ERROR: borrow
let x = String::new();
// We expect the help message to mention cloning.
//~v HELP: consider cloning
let y = x;
// Check error message using a regex
println!("{x}");
//~^ ERROR: /(move)|(borrow)/
}

View file

@ -0,0 +1,39 @@
error[E0382]: borrow of moved value: `x`
--> tests/example_tests/basic_test.rs:13:15
|
7 | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
8 | // Help diagnostics need to be annotated
9 | let y = x;
| - value moved here
...
13 | println!("{x}");
| ^^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
9 | let y = x.clone();
| ++++++++
error[E0382]: borrow of moved value: `x`
--> tests/example_tests/basic_test.rs:22:15
|
16 | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
...
19 | let y = x;
| - value moved here
...
22 | println!("{x}");
| ^^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
19 | let y = x.clone();
| ++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,7 @@
// You can import anything defined in the dependencies table of the crate.
use ui_test::Config;
fn wrong_type() {
let _ = Config::this_function_does_not_exist();
//~^ E0599
}

View file

@ -0,0 +1,20 @@
error[E0599]: no function or associated item named `this_function_does_not_exist` found for struct `Config` in the current scope
--> tests/example_tests/import.rs:5:21
|
5 | let _ = Config::this_function_does_not_exist();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `Config`
|
note: if you're trying to build a new `Config` consider using one of the following associated functions:
Config::rustc
Config::cargo
--> $RUSTUP_HOME/.cargo/git/checkouts/ui_test-2b82183a391bb05c/680bb08/src/config.rs:63:5
|
63 | pub fn rustc(root_dir: impl Into<PathBuf>) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
108 | pub fn cargo(root_dir: impl Into<PathBuf>) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,10 @@
//@check-pass
// This code is expected to compile correctly.
fn correct_borrowing() {
let x = String::new();
let y = &x;
println!("{x}");
println!("{y}");
}

View file

@ -0,0 +1,10 @@
warning: function `correct_borrowing` is never used
--> tests/example_tests/pass_test.rs:4:4
|
4 | fn correct_borrowing() {
| ^^^^^^^^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: 1 warning emitted

View file

@ -7,6 +7,13 @@ repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
publish = false publish = false
[dependencies]
# ui_test dies if we don't specify the version. See oli-obk/ui_test#211
bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
[dev-dependencies] [dev-dependencies]
bevy_ecs = { path = "../bevy_ecs" } bevy_compile_test_utils = { path = "../bevy_compile_test_utils" }
trybuild = "1.0.71"
[[test]]
name = "ui"
harness = false

View file

@ -3,3 +3,5 @@
This crate is separate from `bevy_ecs` and not part of the Bevy workspace in order to not fail `crater` tests for Bevy. The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans). This crate is separate from `bevy_ecs` and not part of the Bevy workspace in order to not fail `crater` tests for Bevy. The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans).
The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)). The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)).
For information on writing tests see [bevy_compile_test_utils/README.md](../bevy_compile_test_utils/README.md).

View file

@ -1,5 +1,3 @@
#[test] fn main() -> bevy_compile_test_utils::ui_test::Result<()> {
fn test() { bevy_compile_test_utils::test("tests/ui")
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/*.rs");
} }

View file

@ -15,6 +15,7 @@ fn main() {
{ {
let gotten: &A = e_mut.get::<A>().unwrap(); let gotten: &A = e_mut.get::<A>().unwrap();
let gotten2: A = e_mut.take::<A>().unwrap(); let gotten2: A = e_mut.take::<A>().unwrap();
//~^ E0502
assert_eq!(gotten, &gotten2); // oops UB assert_eq!(gotten, &gotten2); // oops UB
} }
@ -23,6 +24,7 @@ fn main() {
{ {
let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap(); let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap();
let mut gotten2: A = e_mut.take::<A>().unwrap(); let mut gotten2: A = e_mut.take::<A>().unwrap();
//~^ E0499
assert_eq!(&mut *gotten, &mut gotten2); // oops UB assert_eq!(&mut *gotten, &mut gotten2); // oops UB
} }
@ -31,6 +33,7 @@ fn main() {
{ {
let gotten: &A = e_mut.get::<A>().unwrap(); let gotten: &A = e_mut.get::<A>().unwrap();
e_mut.despawn(); e_mut.despawn();
//~^ E0505
assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB
} }
@ -40,18 +43,21 @@ fn main() {
{ {
let gotten: &A = e_mut.get::<A>().unwrap(); let gotten: &A = e_mut.get::<A>().unwrap();
let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
//~^ E0502
assert_eq!(gotten, &*gotten_mut); // oops UB assert_eq!(gotten, &*gotten_mut); // oops UB
} }
{ {
let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
let gotten: &A = e_mut.get::<A>().unwrap(); let gotten: &A = e_mut.get::<A>().unwrap();
//~^ E0502
assert_eq!(gotten, &*gotten_mut); // oops UB assert_eq!(gotten, &*gotten_mut); // oops UB
} }
{ {
let gotten: &A = e_mut.get::<A>().unwrap(); let gotten: &A = e_mut.get::<A>().unwrap();
e_mut.insert::<B>(B); e_mut.insert::<B>(B);
//~^ E0502
assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB
e_mut.remove::<B>(); e_mut.remove::<B>();
} }
@ -59,6 +65,7 @@ fn main() {
{ {
let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
e_mut.insert::<B>(B); e_mut.insert::<B>(B);
//~^ E0499
assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB
} }
} }

View file

@ -5,68 +5,80 @@ error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as im
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
17 | let gotten2: A = e_mut.take::<A>().unwrap(); 17 | let gotten2: A = e_mut.take::<A>().unwrap();
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
18 | assert_eq!(gotten, &gotten2); // oops UB 18 |
19 | assert_eq!(gotten, &gotten2); // oops UB
| ---------------------------- immutable borrow later used here | ---------------------------- immutable borrow later used here
error[E0499]: cannot borrow `e_mut` as mutable more than once at a time error[E0499]: cannot borrow `e_mut` as mutable more than once at a time
--> tests/ui/entity_ref_mut_lifetime_safety.rs:25:30 --> tests/ui/entity_ref_mut_lifetime_safety.rs:26:30
| |
24 | let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap(); 25 | let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap();
| ----- first mutable borrow occurs here | ----- first mutable borrow occurs here
25 | let mut gotten2: A = e_mut.take::<A>().unwrap(); 26 | let mut gotten2: A = e_mut.take::<A>().unwrap();
| ^^^^^ second mutable borrow occurs here | ^^^^^ second mutable borrow occurs here
26 | assert_eq!(&mut *gotten, &mut gotten2); // oops UB 27 |
28 | assert_eq!(&mut *gotten, &mut gotten2); // oops UB
| ------ first borrow later used here | ------ first borrow later used here
error[E0505]: cannot move out of `e_mut` because it is borrowed error[E0505]: cannot move out of `e_mut` because it is borrowed
--> tests/ui/entity_ref_mut_lifetime_safety.rs:33:9 --> tests/ui/entity_ref_mut_lifetime_safety.rs:35:9
| |
13 | let mut e_mut = world.entity_mut(e); 13 | let mut e_mut = world.entity_mut(e);
| --------- binding `e_mut` declared here | --------- binding `e_mut` declared here
... ...
32 | let gotten: &A = e_mut.get::<A>().unwrap(); 34 | let gotten: &A = e_mut.get::<A>().unwrap();
| ----- borrow of `e_mut` occurs here | ----- borrow of `e_mut` occurs here
33 | e_mut.despawn(); 35 | e_mut.despawn();
| ^^^^^ move out of `e_mut` occurs here | ^^^^^ move out of `e_mut` occurs here
34 | assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB 36 |
37 | assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB
| ------------------------------------------ borrow later used here | ------------------------------------------ borrow later used here
error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable
--> tests/ui/entity_ref_mut_lifetime_safety.rs:42:34 --> tests/ui/entity_ref_mut_lifetime_safety.rs:45:34
| |
41 | let gotten: &A = e_mut.get::<A>().unwrap(); 44 | let gotten: &A = e_mut.get::<A>().unwrap();
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
42 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); 45 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
| ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
43 | assert_eq!(gotten, &*gotten_mut); // oops UB 46 |
47 | assert_eq!(gotten, &*gotten_mut); // oops UB
| -------------------------------- immutable borrow later used here | -------------------------------- immutable borrow later used here
error[E0502]: cannot borrow `e_mut` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `e_mut` as immutable because it is also borrowed as mutable
--> tests/ui/entity_ref_mut_lifetime_safety.rs:48:26 --> tests/ui/entity_ref_mut_lifetime_safety.rs:52:26
| |
47 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); 51 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
48 | let gotten: &A = e_mut.get::<A>().unwrap(); 52 | let gotten: &A = e_mut.get::<A>().unwrap();
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
49 | assert_eq!(gotten, &*gotten_mut); // oops UB 53 |
54 | assert_eq!(gotten, &*gotten_mut); // oops UB
| ---------- mutable borrow later used here | ---------- mutable borrow later used here
error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable
--> tests/ui/entity_ref_mut_lifetime_safety.rs:54:9 --> tests/ui/entity_ref_mut_lifetime_safety.rs:59:9
| |
53 | let gotten: &A = e_mut.get::<A>().unwrap(); 58 | let gotten: &A = e_mut.get::<A>().unwrap();
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
54 | e_mut.insert::<B>(B); 59 | e_mut.insert::<B>(B);
| ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
55 | assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB 60 |
61 | assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB
| ------------------------------------------ immutable borrow later used here | ------------------------------------------ immutable borrow later used here
error[E0499]: cannot borrow `e_mut` as mutable more than once at a time error[E0499]: cannot borrow `e_mut` as mutable more than once at a time
--> tests/ui/entity_ref_mut_lifetime_safety.rs:61:9 --> tests/ui/entity_ref_mut_lifetime_safety.rs:67:9
| |
60 | let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); 66 | let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap();
| ----- first mutable borrow occurs here | ----- first mutable borrow occurs here
61 | e_mut.insert::<B>(B); 67 | e_mut.insert::<B>(B);
| ^^^^^ second mutable borrow occurs here | ^^^^^ second mutable borrow occurs here
62 | assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB 68 |
69 | assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB
| ---------- first borrow later used here | ---------- first borrow later used here
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0499, E0502, E0505.
For more information about an error, try `rustc --explain E0499`.

View file

@ -4,15 +4,13 @@ use bevy_ecs::prelude::*;
struct Foo; struct Foo;
fn on_changed(query: Query<&Foo, Changed<Foo>>) { fn on_changed(query: Query<&Foo, Changed<Foo>>) {
// this should fail to compile
is_exact_size_iterator(query.iter()); is_exact_size_iterator(query.iter());
//~^ E0277
} }
fn on_added(query: Query<&Foo, Added<Foo>>) { fn on_added(query: Query<&Foo, Added<Foo>>) {
// this should fail to compile
is_exact_size_iterator(query.iter()); is_exact_size_iterator(query.iter());
//~^ E0277
} }
fn is_exact_size_iterator<T: ExactSizeIterator>(_iter: T) {} fn is_exact_size_iterator<T: ExactSizeIterator>(_iter: T) {}
fn main() {}

View file

@ -1,7 +1,7 @@
error[E0277]: the trait bound `bevy_ecs::query::Changed<Foo>: ArchetypeFilter` is not satisfied error[E0277]: the trait bound `bevy_ecs::query::Changed<Foo>: ArchetypeFilter` is not satisfied
--> tests/ui/query_exact_sized_iterator_safety.rs:8:28 --> tests/ui/query_exact_sized_iterator_safety.rs:7:28
| |
8 | is_exact_size_iterator(query.iter()); 7 | is_exact_size_iterator(query.iter());
| ---------------------- ^^^^^^^^^^^^ the trait `ArchetypeFilter` is not implemented for `bevy_ecs::query::Changed<Foo>`, which is required by `QueryIter<'_, '_, &Foo, bevy_ecs::query::Changed<Foo>>: ExactSizeIterator` | ---------------------- ^^^^^^^^^^^^ the trait `ArchetypeFilter` is not implemented for `bevy_ecs::query::Changed<Foo>`, which is required by `QueryIter<'_, '_, &Foo, bevy_ecs::query::Changed<Foo>>: ExactSizeIterator`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
@ -15,7 +15,7 @@ error[E0277]: the trait bound `bevy_ecs::query::Changed<Foo>: ArchetypeFilter` i
Or<(F0, F1, F2)> Or<(F0, F1, F2)>
Or<(F0, F1, F2, F3)> Or<(F0, F1, F2, F3)>
Or<(F0, F1, F2, F3, F4)> Or<(F0, F1, F2, F3, F4)>
and $N others and 26 others
= note: required for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Changed<Foo>>` to implement `ExactSizeIterator` = note: required for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Changed<Foo>>` to implement `ExactSizeIterator`
note: required by a bound in `is_exact_size_iterator` note: required by a bound in `is_exact_size_iterator`
--> tests/ui/query_exact_sized_iterator_safety.rs:16:30 --> tests/ui/query_exact_sized_iterator_safety.rs:16:30
@ -24,9 +24,9 @@ note: required by a bound in `is_exact_size_iterator`
| ^^^^^^^^^^^^^^^^^ required by this bound in `is_exact_size_iterator` | ^^^^^^^^^^^^^^^^^ required by this bound in `is_exact_size_iterator`
error[E0277]: the trait bound `bevy_ecs::query::Added<Foo>: ArchetypeFilter` is not satisfied error[E0277]: the trait bound `bevy_ecs::query::Added<Foo>: ArchetypeFilter` is not satisfied
--> tests/ui/query_exact_sized_iterator_safety.rs:13:28 --> tests/ui/query_exact_sized_iterator_safety.rs:12:28
| |
13 | is_exact_size_iterator(query.iter()); 12 | is_exact_size_iterator(query.iter());
| ---------------------- ^^^^^^^^^^^^ the trait `ArchetypeFilter` is not implemented for `bevy_ecs::query::Added<Foo>`, which is required by `QueryIter<'_, '_, &Foo, bevy_ecs::query::Added<Foo>>: ExactSizeIterator` | ---------------------- ^^^^^^^^^^^^ the trait `ArchetypeFilter` is not implemented for `bevy_ecs::query::Added<Foo>`, which is required by `QueryIter<'_, '_, &Foo, bevy_ecs::query::Added<Foo>>: ExactSizeIterator`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
@ -40,10 +40,14 @@ error[E0277]: the trait bound `bevy_ecs::query::Added<Foo>: ArchetypeFilter` is
Or<(F0, F1, F2)> Or<(F0, F1, F2)>
Or<(F0, F1, F2, F3)> Or<(F0, F1, F2, F3)>
Or<(F0, F1, F2, F3, F4)> Or<(F0, F1, F2, F3, F4)>
and $N others and 26 others
= note: required for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Added<Foo>>` to implement `ExactSizeIterator` = note: required for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Added<Foo>>` to implement `ExactSizeIterator`
note: required by a bound in `is_exact_size_iterator` note: required by a bound in `is_exact_size_iterator`
--> tests/ui/query_exact_sized_iterator_safety.rs:16:30 --> tests/ui/query_exact_sized_iterator_safety.rs:16:30
| |
16 | fn is_exact_size_iterator<T: ExactSizeIterator>(_iter: T) {} 16 | fn is_exact_size_iterator<T: ExactSizeIterator>(_iter: T) {}
| ^^^^^^^^^^^^^^^^^ required by this bound in `is_exact_size_iterator` | ^^^^^^^^^^^^^^^^^ required by this bound in `is_exact_size_iterator`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -6,10 +6,8 @@ struct A(usize);
fn system(mut query: Query<&mut A>) { fn system(mut query: Query<&mut A>) {
let iter = query.iter_combinations_mut(); let iter = query.iter_combinations_mut();
// This should fail to compile.
is_iterator(iter) is_iterator(iter)
//~^ E0277
} }
fn is_iterator<T: Iterator>(_iter: T) {} fn is_iterator<T: Iterator>(_iter: T) {}
fn main() {}

View file

@ -1,7 +1,7 @@
error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:10:17 --> tests/ui/query_iter_combinations_mut_iterator_safety.rs:9:17
| |
10 | is_iterator(iter) 9 | is_iterator(iter)
| ----------- ^^^^ the trait `ReadOnlyQueryData` is not implemented for `&mut A`, which is required by `QueryCombinationIter<'_, '_, &mut A, (), _>: Iterator` | ----------- ^^^^ the trait `ReadOnlyQueryData` is not implemented for `&mut A`, which is required by `QueryCombinationIter<'_, '_, &mut A, (), _>: Iterator`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
@ -15,7 +15,7 @@ error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied
AnyOf<(F0, F1, F2)> AnyOf<(F0, F1, F2)>
AnyOf<(F0, F1, F2, F3)> AnyOf<(F0, F1, F2, F3)>
AnyOf<(F0, F1, F2, F3, F4)> AnyOf<(F0, F1, F2, F3, F4)>
and $N others and 34 others
= note: `ReadOnlyQueryData` is implemented for `&A`, but not for `&mut A` = note: `ReadOnlyQueryData` is implemented for `&A`, but not for `&mut A`
= note: required for `QueryCombinationIter<'_, '_, &mut A, (), _>` to implement `Iterator` = note: required for `QueryCombinationIter<'_, '_, &mut A, (), _>` to implement `Iterator`
note: required by a bound in `is_iterator` note: required by a bound in `is_iterator`
@ -23,3 +23,7 @@ note: required by a bound in `is_iterator`
| |
13 | fn is_iterator<T: Iterator>(_iter: T) {} 13 | fn is_iterator<T: Iterator>(_iter: T) {}
| ^^^^^^^^ required by this bound in `is_iterator` | ^^^^^^^^ required by this bound in `is_iterator`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -6,10 +6,8 @@ struct A(usize);
fn system(mut query: Query<&mut A>, e: Entity) { fn system(mut query: Query<&mut A>, e: Entity) {
let iter = query.iter_many_mut([e]); let iter = query.iter_many_mut([e]);
// This should fail to compile.
is_iterator(iter) is_iterator(iter)
//~^ E0277
} }
fn is_iterator<T: Iterator>(_iter: T) {} fn is_iterator<T: Iterator>(_iter: T) {}
fn main() {}

View file

@ -1,7 +1,7 @@
error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied
--> tests/ui/query_iter_many_mut_iterator_safety.rs:10:17 --> tests/ui/query_iter_many_mut_iterator_safety.rs:9:17
| |
10 | is_iterator(iter) 9 | is_iterator(iter)
| ----------- ^^^^ the trait `ReadOnlyQueryData` is not implemented for `&mut A`, which is required by `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>: Iterator` | ----------- ^^^^ the trait `ReadOnlyQueryData` is not implemented for `&mut A`, which is required by `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>: Iterator`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
@ -15,7 +15,7 @@ error[E0277]: the trait bound `&mut A: ReadOnlyQueryData` is not satisfied
AnyOf<(F0, F1, F2)> AnyOf<(F0, F1, F2)>
AnyOf<(F0, F1, F2, F3)> AnyOf<(F0, F1, F2, F3)>
AnyOf<(F0, F1, F2, F3, F4)> AnyOf<(F0, F1, F2, F3, F4)>
and $N others and 34 others
= note: `ReadOnlyQueryData` is implemented for `&A`, but not for `&mut A` = note: `ReadOnlyQueryData` is implemented for `&A`, but not for `&mut A`
= note: required for `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>` to implement `Iterator` = note: required for `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>` to implement `Iterator`
note: required by a bound in `is_iterator` note: required by a bound in `is_iterator`
@ -23,3 +23,7 @@ note: required by a bound in `is_iterator`
| |
13 | fn is_iterator<T: Iterator>(_iter: T) {} 13 | fn is_iterator<T: Iterator>(_iter: T) {}
| ^^^^^^^^ required by this bound in `is_iterator` | ^^^^^^^^ required by this bound in `is_iterator`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -15,48 +15,56 @@ fn main() {
{ {
let data: &Foo = query.get(e).unwrap(); let data: &Foo = query.get(e).unwrap();
let mut data2: Mut<Foo> = query.get_mut(e).unwrap(); let mut data2: Mut<Foo> = query.get_mut(e).unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let mut data2: Mut<Foo> = query.get_mut(e).unwrap(); let mut data2: Mut<Foo> = query.get_mut(e).unwrap();
let data: &Foo = query.get(e).unwrap(); let data: &Foo = query.get(e).unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let data: &Foo = query.single(); let data: &Foo = query.single();
let mut data2: Mut<Foo> = query.single_mut(); let mut data2: Mut<Foo> = query.single_mut();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let mut data2: Mut<Foo> = query.single_mut(); let mut data2: Mut<Foo> = query.single_mut();
let data: &Foo = query.single(); let data: &Foo = query.single();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let data: &Foo = query.get_single().unwrap(); let data: &Foo = query.get_single().unwrap();
let mut data2: Mut<Foo> = query.get_single_mut().unwrap(); let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let mut data2: Mut<Foo> = query.get_single_mut().unwrap(); let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
let data: &Foo = query.get_single().unwrap(); let data: &Foo = query.get_single().unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let data: &Foo = query.iter().next().unwrap(); let data: &Foo = query.iter().next().unwrap();
let mut data2: Mut<Foo> = query.iter_mut().next().unwrap(); let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
{ {
let mut data2: Mut<Foo> = query.iter_mut().next().unwrap(); let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
let data: &Foo = query.iter().next().unwrap(); let data: &Foo = query.iter().next().unwrap();
//~^ E0502
assert_eq!(data, &mut *data2); // oops UB assert_eq!(data, &mut *data2); // oops UB
} }
@ -65,6 +73,7 @@ fn main() {
let mut opt_data_2: Option<Mut<Foo>> = None; let mut opt_data_2: Option<Mut<Foo>> = None;
query.iter().for_each(|data| opt_data = Some(data)); query.iter().for_each(|data| opt_data = Some(data));
query.iter_mut().for_each(|data| opt_data_2 = Some(data)); query.iter_mut().for_each(|data| opt_data_2 = Some(data));
//~^ E0502
assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
} }
@ -73,6 +82,7 @@ fn main() {
let mut opt_data: Option<&Foo> = None; let mut opt_data: Option<&Foo> = None;
query.iter_mut().for_each(|data| opt_data_2 = Some(data)); query.iter_mut().for_each(|data| opt_data_2 = Some(data));
query.iter().for_each(|data| opt_data = Some(data)); query.iter().for_each(|data| opt_data = Some(data));
//~^ E0502
assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
} }
dbg!("bye"); dbg!("bye");

View file

@ -5,95 +5,109 @@ error[E0502]: cannot borrow `query` as mutable because it is also borrowed as im
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
17 | let mut data2: Mut<Foo> = query.get_mut(e).unwrap(); 17 | let mut data2: Mut<Foo> = query.get_mut(e).unwrap();
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
18 | assert_eq!(data, &mut *data2); // oops UB 18 |
19 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here | ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:23:30 --> tests/ui/query_lifetime_safety.rs:24:30
| |
22 | let mut data2: Mut<Foo> = query.get_mut(e).unwrap(); 23 | let mut data2: Mut<Foo> = query.get_mut(e).unwrap();
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
23 | let data: &Foo = query.get(e).unwrap(); 24 | let data: &Foo = query.get(e).unwrap();
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
24 | assert_eq!(data, &mut *data2); // oops UB 25 |
26 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here | ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:29:39 --> tests/ui/query_lifetime_safety.rs:31:39
| |
28 | let data: &Foo = query.single(); 30 | let data: &Foo = query.single();
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
29 | let mut data2: Mut<Foo> = query.single_mut(); 31 | let mut data2: Mut<Foo> = query.single_mut();
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
30 | assert_eq!(data, &mut *data2); // oops UB 32 |
33 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here | ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:35:30 --> tests/ui/query_lifetime_safety.rs:38:30
| |
34 | let mut data2: Mut<Foo> = query.single_mut(); 37 | let mut data2: Mut<Foo> = query.single_mut();
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
35 | let data: &Foo = query.single(); 38 | let data: &Foo = query.single();
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
36 | assert_eq!(data, &mut *data2); // oops UB 39 |
40 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here | ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:41:39 --> tests/ui/query_lifetime_safety.rs:45:39
| |
40 | let data: &Foo = query.get_single().unwrap(); 44 | let data: &Foo = query.get_single().unwrap();
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
41 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap(); 45 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
42 | assert_eq!(data, &mut *data2); // oops UB 46 |
47 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here | ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:47:30 --> tests/ui/query_lifetime_safety.rs:52:30
| |
46 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap(); 51 | let mut data2: Mut<Foo> = query.get_single_mut().unwrap();
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
47 | let data: &Foo = query.get_single().unwrap(); 52 | let data: &Foo = query.get_single().unwrap();
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
48 | assert_eq!(data, &mut *data2); // oops UB 53 |
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:53:39
|
52 | let data: &Foo = query.iter().next().unwrap();
| ----- immutable borrow occurs here
53 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
54 | assert_eq!(data, &mut *data2); // oops UB 54 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:59:30
|
58 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ----- mutable borrow occurs here
59 | let data: &Foo = query.iter().next().unwrap();
| ^^^^^ immutable borrow occurs here
60 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here | ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:67:13 --> tests/ui/query_lifetime_safety.rs:59:39
| |
66 | query.iter().for_each(|data| opt_data = Some(data)); 58 | let data: &Foo = query.iter().next().unwrap();
| ----- immutable borrow occurs here
59 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
60 |
61 | assert_eq!(data, &mut *data2); // oops UB
| ----------------------------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:66:30
|
65 | let mut data2: Mut<Foo> = query.iter_mut().next().unwrap();
| ----- mutable borrow occurs here
66 | let data: &Foo = query.iter().next().unwrap();
| ^^^^^ immutable borrow occurs here
67 |
68 | assert_eq!(data, &mut *data2); // oops UB
| ----- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_lifetime_safety.rs:75:13
|
74 | query.iter().for_each(|data| opt_data = Some(data));
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
67 | query.iter_mut().for_each(|data| opt_data_2 = Some(data)); 75 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
68 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB 76 |
77 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
| -------- immutable borrow later used here | -------- immutable borrow later used here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_lifetime_safety.rs:75:13 --> tests/ui/query_lifetime_safety.rs:84:13
| |
74 | query.iter_mut().for_each(|data| opt_data_2 = Some(data)); 83 | query.iter_mut().for_each(|data| opt_data_2 = Some(data));
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
75 | query.iter().for_each(|data| opt_data = Some(data)); 84 | query.iter().for_each(|data| opt_data = Some(data));
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
76 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB 85 |
86 | assert_eq!(opt_data.unwrap(), &mut *opt_data_2.unwrap()); // oops UB
| ---------- mutable borrow later used here | ---------- mutable borrow later used here
error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0502`.

View file

@ -7,11 +7,13 @@ fn for_loops(mut query: Query<&mut Foo>) {
// this should fail to compile // this should fail to compile
for _ in query.iter_mut() { for _ in query.iter_mut() {
for _ in query.to_readonly().iter() {} for _ in query.to_readonly().iter() {}
//~^ E0502
} }
// this should fail to compile // this should fail to compile
for _ in query.to_readonly().iter() { for _ in query.to_readonly().iter() {
for _ in query.iter_mut() {} for _ in query.iter_mut() {}
//~^ E0502
} }
// this should *not* fail to compile // this should *not* fail to compile
@ -37,6 +39,7 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
// This solves "temporary value dropped while borrowed" // This solves "temporary value dropped while borrowed"
let readonly_query = query.to_readonly(); let readonly_query = query.to_readonly();
//~^ E0502
let ref_foo = readonly_query.single(); let ref_foo = readonly_query.single();
@ -53,6 +56,7 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
let ref_foo = readonly_query.single(); let ref_foo = readonly_query.single();
let mut mut_foo = query.single_mut(); let mut mut_foo = query.single_mut();
//~^ E0502
println!("{ref_foo:?}"); println!("{ref_foo:?}");
@ -71,5 +75,3 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
println!("{readonly_foo:?}, {query_foo:?}"); println!("{readonly_foo:?}, {query_foo:?}");
} }
} }
fn main() {}

View file

@ -10,36 +10,40 @@ error[E0502]: cannot borrow `query` as immutable because it is also borrowed as
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_to_readonly.rs:14:18 --> tests/ui/query_to_readonly.rs:15:18
| |
13 | for _ in query.to_readonly().iter() { 14 | for _ in query.to_readonly().iter() {
| -------------------------- | --------------------------
| | | |
| immutable borrow occurs here | immutable borrow occurs here
| immutable borrow later used here | immutable borrow later used here
14 | for _ in query.iter_mut() {} 15 | for _ in query.iter_mut() {}
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable
--> tests/ui/query_to_readonly.rs:39:30 --> tests/ui/query_to_readonly.rs:41:30
| |
36 | let mut mut_foo = query.single_mut(); 38 | let mut mut_foo = query.single_mut();
| ----- mutable borrow occurs here | ----- mutable borrow occurs here
... ...
39 | let readonly_query = query.to_readonly(); 41 | let readonly_query = query.to_readonly();
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
... ...
43 | *mut_foo = Foo; 46 | *mut_foo = Foo;
| ------- mutable borrow later used here | ------- mutable borrow later used here
error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable
--> tests/ui/query_to_readonly.rs:55:27 --> tests/ui/query_to_readonly.rs:58:27
| |
51 | let readonly_query = query.to_readonly(); 54 | let readonly_query = query.to_readonly();
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
... ...
55 | let mut mut_foo = query.single_mut(); 58 | let mut mut_foo = query.single_mut();
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
56 | ...
57 | println!("{ref_foo:?}"); 61 | println!("{ref_foo:?}");
| ----------- immutable borrow later used here | ----------- immutable borrow later used here
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0502`.

View file

@ -17,6 +17,7 @@ fn main() {
{ {
let mut lens_a = query.transmute_lens::<&mut Foo>(); let mut lens_a = query.transmute_lens::<&mut Foo>();
let mut lens_b = query.transmute_lens::<&mut Foo>(); let mut lens_b = query.transmute_lens::<&mut Foo>();
//~^ E0499
let mut query_a = lens_a.query(); let mut query_a = lens_a.query();
let mut query_b = lens_b.query(); let mut query_b = lens_b.query();
@ -31,6 +32,7 @@ fn main() {
let mut query_a = lens.query(); let mut query_a = lens.query();
let mut query_b = lens.query(); let mut query_b = lens.query();
//~^ E0499
let a = query_a.single_mut(); let a = query_a.single_mut();
let b = query_b.single_mut(); // oops 2 mutable references to same Foo let b = query_b.single_mut(); // oops 2 mutable references to same Foo

View file

@ -5,17 +5,21 @@ error[E0499]: cannot borrow `query` as mutable more than once at a time
| ----- first mutable borrow occurs here | ----- first mutable borrow occurs here
19 | let mut lens_b = query.transmute_lens::<&mut Foo>(); 19 | let mut lens_b = query.transmute_lens::<&mut Foo>();
| ^^^^^ second mutable borrow occurs here | ^^^^^ second mutable borrow occurs here
20 | ...
21 | let mut query_a = lens_a.query(); 22 | let mut query_a = lens_a.query();
| ------ first borrow later used here | ------ first borrow later used here
error[E0499]: cannot borrow `lens` as mutable more than once at a time error[E0499]: cannot borrow `lens` as mutable more than once at a time
--> tests/ui/query_transmute_safety.rs:33:27 --> tests/ui/query_transmute_safety.rs:34:27
| |
32 | let mut query_a = lens.query(); 33 | let mut query_a = lens.query();
| ---- first mutable borrow occurs here | ---- first mutable borrow occurs here
33 | let mut query_b = lens.query(); 34 | let mut query_b = lens.query();
| ^^^^ second mutable borrow occurs here | ^^^^ second mutable borrow occurs here
34 | ...
35 | let a = query_a.single_mut(); 37 | let a = query_a.single_mut();
| ------- first borrow later used here | ------- first borrow later used here
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0499`.

View file

@ -10,12 +10,11 @@ struct Mutable<'w, 's> {
} }
fn main() { fn main() {
// Ideally we'd use:
// let mut world = World::default(); let mut world = World::default();
// let state = SystemState::<Mutable>::new(&mut world); let state = SystemState::<Mutable>::new(&mut world);
// state.get(&world); state.get(&world);
// But that makes the test show absolute paths //~^ E0277
assert_readonly::<Mutable>();
} }
fn assert_readonly<P>() fn assert_readonly<P>()

View file

@ -1,36 +1,32 @@
warning: unused import: `SystemState`
--> tests/ui/system_param_derive_readonly.rs:2:58
|
2 | use bevy_ecs::system::{ReadOnlySystemParam, SystemParam, SystemState};
| ^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyQueryData` is not satisfied error[E0277]: the trait bound `&'static mut Foo: ReadOnlyQueryData` is not satisfied
--> tests/ui/system_param_derive_readonly.rs:18:23 --> tests/ui/system_param_derive_readonly.rs:16:11
| |
18 | assert_readonly::<Mutable>(); 16 | state.get(&world);
| ^^^^^^^ the trait `ReadOnlyQueryData` is not implemented for `&'static mut Foo`, which is required by `Mutable<'_, '_>: ReadOnlySystemParam` | ^^^ the trait `ReadOnlyQueryData` is not implemented for `&'static mut Foo`, which is required by `Mutable<'_, '_>: ReadOnlySystemParam`
| |
= help: the following other types implement trait `ReadOnlyQueryData`: = help: the following other types implement trait `ReadOnlyQueryData`:
bevy_ecs::change_detection::Ref<'__w, T> bevy_ecs::change_detection::Ref<'__w, T>
Has<T> Has<T>
AnyOf<()> AnyOf<()>
AnyOf<(F0,)> AnyOf<(F0,)>
AnyOf<(F0, F1)> AnyOf<(F0, F1)>
AnyOf<(F0, F1, F2)> AnyOf<(F0, F1, F2)>
AnyOf<(F0, F1, F2, F3)> AnyOf<(F0, F1, F2, F3)>
AnyOf<(F0, F1, F2, F3, F4)> AnyOf<(F0, F1, F2, F3, F4)>
and $N others and 34 others
= note: `ReadOnlyQueryData` is implemented for `&'static Foo`, but not for `&'static mut Foo` = note: `ReadOnlyQueryData` is implemented for `&'static Foo`, but not for `&'static mut Foo`
= note: required for `bevy_ecs::system::Query<'_, '_, &'static mut Foo>` to implement `ReadOnlySystemParam` = note: required for `bevy_ecs::system::Query<'_, '_, &'static mut Foo>` to implement `ReadOnlySystemParam`
= note: 1 redundant requirement hidden = note: 1 redundant requirement hidden
= note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam` = note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam`
note: required by a bound in `assert_readonly` note: required by a bound in `SystemState::<Param>::get`
--> tests/ui/system_param_derive_readonly.rs:23:8 --> $BEVY_ROOT/crates/bevy_ecs/src/system/function_system.rs:215:16
| |
21 | fn assert_readonly<P>() 213 | pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
| --------------- required by a bound in this function | --- required by a bound in this associated function
22 | where 214 | where
23 | P: ReadOnlySystemParam, 215 | Param: ReadOnlySystemParam,
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_readonly` | ^^^^^^^^^^^^^^^^^^^ required by this bound in `SystemState::<Param>::get`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -6,8 +6,6 @@ struct A(usize);
fn system(mut query: Query<&mut A>, e: Entity) { fn system(mut query: Query<&mut A>, e: Entity) {
let a1 = query.get_mut(e).unwrap(); let a1 = query.get_mut(e).unwrap();
let a2 = query.get_mut(e).unwrap(); let a2 = query.get_mut(e).unwrap();
// this should fail to compile //~^ E0499
println!("{} {}", a1.0, a2.0); println!("{} {}", a1.0, a2.0);
} }
fn main() {}

View file

@ -5,6 +5,10 @@ error[E0499]: cannot borrow `query` as mutable more than once at a time
| ----- first mutable borrow occurs here | ----- first mutable borrow occurs here
8 | let a2 = query.get_mut(e).unwrap(); 8 | let a2 = query.get_mut(e).unwrap();
| ^^^^^ second mutable borrow occurs here | ^^^^^ second mutable borrow occurs here
9 | // this should fail to compile 9 |
10 | println!("{} {}", a1.0, a2.0); 10 | println!("{} {}", a1.0, a2.0);
| -- first borrow later used here | -- first borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0499`.

View file

@ -6,8 +6,6 @@ struct A(usize);
fn system(mut query: Query<&mut A>, e: Entity) { fn system(mut query: Query<&mut A>, e: Entity) {
let a1 = query.get_many([e, e]).unwrap(); let a1 = query.get_many([e, e]).unwrap();
let a2 = query.get_mut(e).unwrap(); let a2 = query.get_mut(e).unwrap();
// this should fail to compile //~^ E0502
println!("{} {}", a1[0].0, a2.0); println!("{} {}", a1[0].0, a2.0);
} }
fn main() {}

View file

@ -5,6 +5,10 @@ error[E0502]: cannot borrow `query` as mutable because it is also borrowed as im
| ----- immutable borrow occurs here | ----- immutable borrow occurs here
8 | let a2 = query.get_mut(e).unwrap(); 8 | let a2 = query.get_mut(e).unwrap();
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
9 | // this should fail to compile 9 |
10 | println!("{} {}", a1[0].0, a2.0); 10 | println!("{} {}", a1[0].0, a2.0);
| ----- immutable borrow later used here | ----- immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.

View file

@ -6,8 +6,6 @@ struct A(usize);
fn system(mut query: Query<&mut A>, e: Entity) { fn system(mut query: Query<&mut A>, e: Entity) {
let a1 = query.get_many_mut([e, e]).unwrap(); let a1 = query.get_many_mut([e, e]).unwrap();
let a2 = query.get_mut(e).unwrap(); let a2 = query.get_mut(e).unwrap();
// this should fail to compile //~^ E0499
println!("{} {}", a1[0].0, a2.0); println!("{} {}", a1[0].0, a2.0);
} }
fn main() {}

View file

@ -5,6 +5,10 @@ error[E0499]: cannot borrow `query` as mutable more than once at a time
| ----- first mutable borrow occurs here | ----- first mutable borrow occurs here
8 | let a2 = query.get_mut(e).unwrap(); 8 | let a2 = query.get_mut(e).unwrap();
| ^^^^^ second mutable borrow occurs here | ^^^^^ second mutable borrow occurs here
9 | // this should fail to compile 9 |
10 | println!("{} {}", a1[0].0, a2.0); 10 | println!("{} {}", a1[0].0, a2.0);
| ----- first borrow later used here | ----- first borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0499`.

View file

@ -8,10 +8,8 @@ fn system(mut query: Query<&mut A>) {
let a = &mut *iter.next().unwrap(); let a = &mut *iter.next().unwrap();
let mut iter2 = query.iter_mut(); let mut iter2 = query.iter_mut();
//~^ E0499
let _ = &mut *iter2.next().unwrap(); let _ = &mut *iter2.next().unwrap();
// this should fail to compile
println!("{}", a.0); println!("{}", a.0);
} }
fn main() {}

View file

@ -9,3 +9,7 @@ error[E0499]: cannot borrow `query` as mutable more than once at a time
... ...
14 | println!("{}", a.0); 14 | println!("{}", a.0);
| --- first borrow later used here | --- first borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0499`.

View file

@ -6,10 +6,8 @@ struct A(usize);
fn system(mut query: Query<&mut A>, e: Entity) { fn system(mut query: Query<&mut A>, e: Entity) {
let mut results = Vec::new(); let mut results = Vec::new();
let mut iter = query.iter_many_mut([e, e]); let mut iter = query.iter_many_mut([e, e]);
//~v E0499
while let Some(a) = iter.fetch_next() { while let Some(a) = iter.fetch_next() {
// this should fail to compile
results.push(a); results.push(a);
} }
} }
fn main() {}

View file

@ -1,8 +1,11 @@
error[E0499]: cannot borrow `iter` as mutable more than once at a time error[E0499]: cannot borrow `iter` as mutable more than once at a time
--> tests/ui/system_query_iter_many_mut_lifetime_safety.rs:9:25 --> tests/ui/system_query_iter_many_mut_lifetime_safety.rs:10:25
| |
9 | while let Some(a) = iter.fetch_next() { 10 | while let Some(a) = iter.fetch_next() {
| ^^^^ `iter` was mutably borrowed here in the previous iteration of the loop | ^^^^ `iter` was mutably borrowed here in the previous iteration of the loop
10 | // this should fail to compile
11 | results.push(a); 11 | results.push(a);
| ------- first borrow used here, in later iteration of loop | ------- first borrow used here, in later iteration of loop
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0499`.

View file

@ -8,6 +8,7 @@ fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Entity) {
let mut b = q2.get_mut(e).unwrap(); let mut b = q2.get_mut(e).unwrap();
let q1 = queries.p1(); let q1 = queries.p1();
//~^ E0499
let a = q1.get(e).unwrap(); let a = q1.get(e).unwrap();
// this should fail to compile // this should fail to compile
@ -19,10 +20,9 @@ fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Entity)
let a = q1.get(e).unwrap(); let a = q1.get(e).unwrap();
let mut q2 = queries.p0(); let mut q2 = queries.p0();
//~^ E0499
let mut b = q2.get_mut(e).unwrap(); let mut b = q2.get_mut(e).unwrap();
// this should fail to compile // this should fail to compile
b.0 = a.0 b.0 = a.0
} }
fn main() {}

View file

@ -7,17 +7,21 @@ error[E0499]: cannot borrow `queries` as mutable more than once at a time
10 | let q1 = queries.p1(); 10 | let q1 = queries.p1();
| ^^^^^^^ second mutable borrow occurs here | ^^^^^^^ second mutable borrow occurs here
... ...
14 | b.0 = a.0 15 | b.0 = a.0
| - first borrow later used here | - first borrow later used here
error[E0499]: cannot borrow `queries` as mutable more than once at a time error[E0499]: cannot borrow `queries` as mutable more than once at a time
--> tests/ui/system_query_set_get_lifetime_safety.rs:21:18 --> tests/ui/system_query_set_get_lifetime_safety.rs:22:18
| |
18 | let q1 = queries.p1(); 19 | let q1 = queries.p1();
| ------- first mutable borrow occurs here | ------- first mutable borrow occurs here
... ...
21 | let mut q2 = queries.p0(); 22 | let mut q2 = queries.p0();
| ^^^^^^^ second mutable borrow occurs here | ^^^^^^^ second mutable borrow occurs here
... ...
25 | b.0 = a.0 27 | b.0 = a.0
| --- first borrow later used here | --- first borrow later used here
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0499`.

View file

@ -9,10 +9,10 @@ fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>) {
let mut b = iter2.next().unwrap(); let mut b = iter2.next().unwrap();
let q1 = queries.p1(); let q1 = queries.p1();
//~^ E0499
let mut iter = q1.iter(); let mut iter = q1.iter();
let a = &*iter.next().unwrap(); let a = &*iter.next().unwrap();
// this should fail to compile
b.0 = a.0 b.0 = a.0
} }
@ -22,11 +22,9 @@ fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>) {
let a = &*iter.next().unwrap(); let a = &*iter.next().unwrap();
let mut q2 = queries.p0(); let mut q2 = queries.p0();
//~^ E0499
let mut iter2 = q2.iter_mut(); let mut iter2 = q2.iter_mut();
let mut b = iter2.next().unwrap(); let mut b = iter2.next().unwrap();
// this should fail to compile
b.0 = a.0; b.0 = a.0;
} }
fn main() {}

View file

@ -21,3 +21,7 @@ error[E0499]: cannot borrow `queries` as mutable more than once at a time
... ...
29 | b.0 = a.0; 29 | b.0 = a.0;
| --- first borrow later used here | --- first borrow later used here
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0499`.

View file

@ -18,11 +18,9 @@ impl State {
let a1 = q1.get(entity).unwrap(); let a1 = q1.get(entity).unwrap();
let mut q2 = self.state_w.get_mut(world); let mut q2 = self.state_w.get_mut(world);
//~^ E0502
let _ = q2.get_mut(entity).unwrap(); let _ = q2.get_mut(entity).unwrap();
// this should fail to compile
println!("{}", a1.0); println!("{}", a1.0);
} }
} }
fn main() {}

View file

@ -9,3 +9,7 @@ error[E0502]: cannot borrow `*world` as mutable because it is also borrowed as i
... ...
24 | println!("{}", a1.0); 24 | println!("{}", a1.0);
| ---- immutable borrow later used here | ---- immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.

View file

@ -18,11 +18,9 @@ impl State {
let a1 = q1.iter().next().unwrap(); let a1 = q1.iter().next().unwrap();
let mut q2 = self.state_w.get_mut(world); let mut q2 = self.state_w.get_mut(world);
//~^ E0502
let _ = q2.iter_mut().next().unwrap(); let _ = q2.iter_mut().next().unwrap();
// this should fail to compile
println!("{}", a1.0); println!("{}", a1.0);
} }
} }
fn main() {}

View file

@ -9,3 +9,7 @@ error[E0502]: cannot borrow `*world` as mutable because it is also borrowed as i
... ...
24 | println!("{}", a1.0); 24 | println!("{}", a1.0);
| ---- immutable borrow later used here | ---- immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.

View file

@ -16,6 +16,7 @@ fn main() {
assert_eq!( assert_eq!(
// this should fail to compile due to the later use of mut_vec // this should fail to compile due to the later use of mut_vec
query.iter().collect::<Vec<&A>>(), query.iter().collect::<Vec<&A>>(),
//~^ E0502
vec![&A(1), &A(2)], vec![&A(1), &A(2)],
"both components returned by iter of &mut" "both components returned by iter of &mut"
); );

View file

@ -7,5 +7,9 @@ error[E0502]: cannot borrow `query` as immutable because it is also borrowed as
18 | query.iter().collect::<Vec<&A>>(), 18 | query.iter().collect::<Vec<&A>>(),
| ^^^^^ immutable borrow occurs here | ^^^^^ immutable borrow occurs here
... ...
23 | mut_vec.iter().map(|m| **m).collect::<Vec<A>>(), 24 | mut_vec.iter().map(|m| **m).collect::<Vec<A>>(),
| ------- mutable borrow later used here | ------- mutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.

View file

@ -6,6 +6,7 @@ struct Foo;
#[derive(QueryData)] #[derive(QueryData)]
struct MutableUnmarked { struct MutableUnmarked {
//~v E0277
a: &'static mut Foo, a: &'static mut Foo,
} }
@ -17,7 +18,6 @@ struct MutableMarked {
#[derive(QueryData)] #[derive(QueryData)]
struct NestedMutableUnmarked { struct NestedMutableUnmarked {
//~v E0277
a: MutableMarked, a: MutableMarked,
} }
fn main() {}

View file

@ -1,30 +1,30 @@
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyQueryData` is not satisfied error[E0277]: the trait bound `&'static mut Foo: ReadOnlyQueryData` is not satisfied
--> tests/ui/world_query_derive.rs:9:8 --> tests/ui/world_query_derive.rs:10:8
| |
9 | a: &'static mut Foo, 10 | a: &'static mut Foo,
| ^^^^^^^^^^^^^^^^ the trait `ReadOnlyQueryData` is not implemented for `&'static mut Foo` | ^^^^^^^^^^^^^^^^ the trait `ReadOnlyQueryData` is not implemented for `&'static mut Foo`
| |
= help: the following other types implement trait `ReadOnlyQueryData`: = help: the following other types implement trait `ReadOnlyQueryData`:
MutableUnmarked MutableUnmarked
MutableMarkedReadOnly MutableMarkedReadOnly
NestedMutableUnmarked NestedMutableUnmarked
bevy_ecs::change_detection::Ref<'__w, T> bevy_ecs::change_detection::Ref<'__w, T>
Has<T> Has<T>
AnyOf<()> AnyOf<()>
AnyOf<(F0,)> AnyOf<(F0,)>
AnyOf<(F0, F1)> AnyOf<(F0, F1)>
and $N others and 37 others
note: required by a bound in `_::assert_readonly` note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:7:10 --> tests/ui/world_query_derive.rs:7:10
| |
7 | #[derive(QueryData)] 7 | #[derive(QueryData)]
| ^^^^^^^^^ required by this bound in `assert_readonly` | ^^^^^^^^^ required by this bound in `assert_readonly`
= note: this error originates in the derive macro `QueryData` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `QueryData` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MutableMarked: ReadOnlyQueryData` is not satisfied error[E0277]: the trait bound `MutableMarked: ReadOnlyQueryData` is not satisfied
--> tests/ui/world_query_derive.rs:20:8 --> tests/ui/world_query_derive.rs:22:8
| |
20 | a: MutableMarked, 22 | a: MutableMarked,
| ^^^^^^^^^^^^^ the trait `ReadOnlyQueryData` is not implemented for `MutableMarked` | ^^^^^^^^^^^^^ the trait `ReadOnlyQueryData` is not implemented for `MutableMarked`
| |
= help: the following other types implement trait `ReadOnlyQueryData`: = help: the following other types implement trait `ReadOnlyQueryData`:
@ -36,10 +36,14 @@ error[E0277]: the trait bound `MutableMarked: ReadOnlyQueryData` is not satisfie
AnyOf<()> AnyOf<()>
AnyOf<(F0,)> AnyOf<(F0,)>
AnyOf<(F0, F1)> AnyOf<(F0, F1)>
and $N others and 37 others
note: required by a bound in `_::assert_readonly` note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:18:10 --> tests/ui/world_query_derive.rs:19:10
| |
18 | #[derive(QueryData)] 19 | #[derive(QueryData)]
| ^^^^^^^^^ required by this bound in `assert_readonly` | ^^^^^^^^^ required by this bound in `assert_readonly`
= note: this error originates in the derive macro `QueryData` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `QueryData` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -8,5 +8,12 @@ license = "MIT OR Apache-2.0"
publish = false publish = false
[dependencies] [dependencies]
bevy_derive = { path = "../bevy_derive" } # ui_test dies if we don't specify the version. See oli-obk/ui_test#211
trybuild = "1.0.71" bevy_derive = { path = "../bevy_derive", version = "0.14.0-dev" }
[dev-dependencies]
bevy_compile_test_utils = { path = "../bevy_compile_test_utils" }
[[test]]
name = "derive"
harness = false

View file

@ -4,3 +4,5 @@ This crate is not part of the Bevy workspace in order to not fail `crater` tests
The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans). The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans).
The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)). The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)).
For information on writing tests see [bevy_compile_test_utils/README.md](../bevy_compile_test_utils/README.md).

View file

@ -1,6 +0,0 @@
#[test]
fn test() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/deref_derive/*.fail.rs");
t.pass("tests/deref_derive/*.pass.rs");
}

View file

@ -1,11 +0,0 @@
error: unexpected token in attribute
--> tests/deref_derive/invalid_attribute.fail.rs:6:34
|
6 | struct TupleStruct(usize, #[deref()] String);
| ^
error: unexpected token in attribute
--> tests/deref_derive/invalid_attribute.fail.rs:11:12
|
11 | #[deref()]
| ^

View file

@ -3,13 +3,16 @@ use bevy_derive::Deref;
// Reason: `#[deref]` doesn't take any arguments // Reason: `#[deref]` doesn't take any arguments
#[derive(Deref)] #[derive(Deref)]
struct TupleStruct(usize, #[deref()] String); struct TupleStruct(
usize,
#[deref()] String
//~^ ERROR: unexpected token
);
#[derive(Deref)] #[derive(Deref)]
struct Struct { struct Struct {
foo: usize, foo: usize,
#[deref()] #[deref()]
//~^ ERROR: unexpected token
bar: String, bar: String,
} }
fn main() {}

View file

@ -0,0 +1,14 @@
error: unexpected token in attribute
--> tests/deref_derive/invalid_attribute_fail.rs:8:12
|
8 | #[deref()] String
| ^
error: unexpected token in attribute
--> tests/deref_derive/invalid_attribute_fail.rs:15:12
|
15 | #[deref()]
| ^
error: aborting due to 2 previous errors

View file

@ -1,9 +0,0 @@
use bevy_derive::Deref;
#[derive(Deref)]
struct UnitStruct;
#[derive(Deref)]
enum Enum {}
fn main() {}

View file

@ -0,0 +1,9 @@
use bevy_derive::Deref;
#[derive(Deref)]
//~^ ERROR: cannot be derived on field-less structs
struct UnitStruct;
#[derive(Deref)]
//~^ ERROR: can only be derived on structs
enum Enum {}

View file

@ -1,5 +1,5 @@
error: Deref cannot be derived on field-less structs error: Deref cannot be derived on field-less structs
--> tests/deref_derive/invalid_item.fail.rs:3:10 --> tests/deref_derive/invalid_item_fail.rs:3:10
| |
3 | #[derive(Deref)] 3 | #[derive(Deref)]
| ^^^^^ | ^^^^^
@ -7,9 +7,12 @@ error: Deref cannot be derived on field-less structs
= note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info)
error: Deref can only be derived on structs error: Deref can only be derived on structs
--> tests/deref_derive/invalid_item.fail.rs:6:10 --> tests/deref_derive/invalid_item_fail.rs:7:10
| |
6 | #[derive(Deref)] 7 | #[derive(Deref)]
| ^^^^^ | ^^^^^
| |
= note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -1,12 +1,12 @@
use bevy_derive::Deref; use bevy_derive::Deref;
#[derive(Deref)] #[derive(Deref)]
//~^ ERROR: requires one field to have
struct TupleStruct(usize, String); struct TupleStruct(usize, String);
#[derive(Deref)] #[derive(Deref)]
//~^ ERROR: requires one field to have
struct Struct { struct Struct {
foo: usize, foo: usize,
bar: String, bar: String,
} }
fn main() {}

View file

@ -1,5 +1,5 @@
error: deriving Deref on multi-field structs requires one field to have the `#[deref]` attribute error: deriving Deref on multi-field structs requires one field to have the `#[deref]` attribute
--> tests/deref_derive/missing_attribute.fail.rs:3:10 --> tests/deref_derive/missing_attribute_fail.rs:3:10
| |
3 | #[derive(Deref)] 3 | #[derive(Deref)]
| ^^^^^ | ^^^^^
@ -7,9 +7,12 @@ error: deriving Deref on multi-field structs requires one field to have the `#[d
= note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info)
error: deriving Deref on multi-field structs requires one field to have the `#[deref]` attribute error: deriving Deref on multi-field structs requires one field to have the `#[deref]` attribute
--> tests/deref_derive/missing_attribute.fail.rs:6:10 --> tests/deref_derive/missing_attribute_fail.rs:7:10
| |
6 | #[derive(Deref)] 7 | #[derive(Deref)]
| ^^^^^ | ^^^^^
| |
= note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Deref` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -1,14 +0,0 @@
use bevy_derive::Deref;
#[derive(Deref)]
struct TupleStruct(#[deref] usize, #[deref] String);
#[derive(Deref)]
struct Struct {
#[deref]
foo: usize,
#[deref]
bar: String,
}
fn main() {}

View file

@ -1,11 +0,0 @@
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_derive/multiple_attributes.fail.rs:4:36
|
4 | struct TupleStruct(#[deref] usize, #[deref] String);
| ^^^^^^^^
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_derive/multiple_attributes.fail.rs:10:5
|
10 | #[deref]
| ^^^^^^^^

View file

@ -0,0 +1,17 @@
use bevy_derive::Deref;
#[derive(Deref)]
struct TupleStruct(
#[deref] usize,
#[deref] String
//~^ ERROR: can only be used on a single field
);
#[derive(Deref)]
struct Struct {
#[deref]
foo: usize,
#[deref]
//~^ ERROR: can only be used on a single field
bar: String,
}

View file

@ -0,0 +1,14 @@
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_derive/multiple_attributes_fail.rs:6:5
|
6 | #[deref] String
| ^^^^^^^^
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_derive/multiple_attributes_fail.rs:14:5
|
14 | #[deref]
| ^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -1,3 +1,4 @@
//@check-pass
use bevy_derive::Deref; use bevy_derive::Deref;
#[derive(Deref)] #[derive(Deref)]
@ -17,6 +18,7 @@ struct Struct {
fn main() { fn main() {
let value = TupleStruct(123, "Hello world!".to_string()); let value = TupleStruct(123, "Hello world!".to_string());
let _: &String = &*value; let _: &String = &*value;
let _ = value.0;
let value = Struct { let value = Struct {
#[cfg(test)] #[cfg(test)]
@ -25,4 +27,5 @@ fn main() {
baz: 321, baz: 321,
}; };
let _: &String = &*value; let _: &String = &*value;
let _ = value.baz;
} }

View file

@ -1,3 +1,4 @@
//@check-pass
use bevy_derive::Deref; use bevy_derive::Deref;
#[derive(Deref)] #[derive(Deref)]

View file

@ -1,6 +0,0 @@
#[test]
fn test() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/deref_mut_derive/*.fail.rs");
t.pass("tests/deref_mut_derive/*.pass.rs");
}

View file

@ -1,11 +0,0 @@
error: unexpected token in attribute
--> tests/deref_mut_derive/invalid_attribute.fail.rs:7:34
|
7 | struct TupleStruct(usize, #[deref()] String);
| ^
error: unexpected token in attribute
--> tests/deref_mut_derive/invalid_attribute.fail.rs:20:12
|
20 | #[deref()]
| ^

View file

@ -4,7 +4,11 @@ use std::ops::Deref;
// Reason: `#[deref]` doesn't take any arguments // Reason: `#[deref]` doesn't take any arguments
#[derive(DerefMut)] #[derive(DerefMut)]
struct TupleStruct(usize, #[deref()] String); struct TupleStruct(
usize,
#[deref()] String
//~^ ERROR: unexpected token
);
impl Deref for TupleStruct { impl Deref for TupleStruct {
type Target = String; type Target = String;
@ -18,6 +22,7 @@ impl Deref for TupleStruct {
struct Struct { struct Struct {
foo: usize, foo: usize,
#[deref()] #[deref()]
//~^ ERROR: unexpected token
bar: String, bar: String,
} }
@ -28,5 +33,3 @@ impl Deref for Struct {
&self.bar &self.bar
} }
} }
fn main() {}

View file

@ -0,0 +1,14 @@
error: unexpected token in attribute
--> tests/deref_mut_derive/invalid_attribute_fail.rs:9:12
|
9 | #[deref()] String
| ^
error: unexpected token in attribute
--> tests/deref_mut_derive/invalid_attribute_fail.rs:24:12
|
24 | #[deref()]
| ^
error: aborting due to 2 previous errors

View file

@ -1,9 +1,9 @@
use bevy_derive::DerefMut; use bevy_derive::DerefMut;
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ ERROR: cannot be derived on field-less structs
struct UnitStruct; struct UnitStruct;
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ ERROR: can only be derived on structs
enum Enum {} enum Enum {}
fn main() {}

View file

@ -1,5 +1,5 @@
error: DerefMut cannot be derived on field-less structs error: DerefMut cannot be derived on field-less structs
--> tests/deref_mut_derive/invalid_item.fail.rs:3:10 --> tests/deref_mut_derive/invalid_item_fail.rs:3:10
| |
3 | #[derive(DerefMut)] 3 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
@ -7,9 +7,12 @@ error: DerefMut cannot be derived on field-less structs
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: DerefMut can only be derived on structs error: DerefMut can only be derived on structs
--> tests/deref_mut_derive/invalid_item.fail.rs:6:10 --> tests/deref_mut_derive/invalid_item_fail.rs:7:10
| |
6 | #[derive(DerefMut)] 7 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
| |
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -2,6 +2,7 @@ use bevy_derive::DerefMut;
use std::ops::Deref; use std::ops::Deref;
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ E0308
struct TupleStruct(#[deref] usize, String); struct TupleStruct(#[deref] usize, String);
impl Deref for TupleStruct { impl Deref for TupleStruct {
@ -13,6 +14,7 @@ impl Deref for TupleStruct {
} }
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ E0308
struct Struct { struct Struct {
#[deref] #[deref]
foo: usize, foo: usize,
@ -26,5 +28,3 @@ impl Deref for Struct {
&self.bar &self.bar
} }
} }
fn main() {}

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types error[E0308]: mismatched types
--> tests/deref_mut_derive/mismatched_target_type.fail.rs:4:10 --> tests/deref_mut_derive/mismatched_target_type_fail.rs:4:10
| |
4 | #[derive(DerefMut)] 4 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
@ -12,9 +12,9 @@ error[E0308]: mismatched types
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types error[E0308]: mismatched types
--> tests/deref_mut_derive/mismatched_target_type.fail.rs:15:10 --> tests/deref_mut_derive/mismatched_target_type_fail.rs:16:10
| |
15 | #[derive(DerefMut)] 16 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
| | | |
| expected `&mut String`, found `&mut usize` | expected `&mut String`, found `&mut usize`
@ -23,3 +23,7 @@ error[E0308]: mismatched types
= note: expected mutable reference `&mut String` = note: expected mutable reference `&mut String`
found mutable reference `&mut usize` found mutable reference `&mut usize`
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -2,6 +2,7 @@ use bevy_derive::DerefMut;
use std::ops::Deref; use std::ops::Deref;
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ ERROR: requires one field to have
struct TupleStruct(usize, String); struct TupleStruct(usize, String);
impl Deref for TupleStruct { impl Deref for TupleStruct {
@ -13,6 +14,7 @@ impl Deref for TupleStruct {
} }
#[derive(DerefMut)] #[derive(DerefMut)]
//~^ ERROR: requires one field to have
struct Struct { struct Struct {
foo: usize, foo: usize,
bar: String, bar: String,
@ -25,5 +27,3 @@ impl Deref for Struct {
&self.bar &self.bar
} }
} }
fn main() {}

View file

@ -1,5 +1,5 @@
error: deriving DerefMut on multi-field structs requires one field to have the `#[deref]` attribute error: deriving DerefMut on multi-field structs requires one field to have the `#[deref]` attribute
--> tests/deref_mut_derive/missing_attribute.fail.rs:4:10 --> tests/deref_mut_derive/missing_attribute_fail.rs:4:10
| |
4 | #[derive(DerefMut)] 4 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
@ -7,9 +7,12 @@ error: deriving DerefMut on multi-field structs requires one field to have the `
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: deriving DerefMut on multi-field structs requires one field to have the `#[deref]` attribute error: deriving DerefMut on multi-field structs requires one field to have the `#[deref]` attribute
--> tests/deref_mut_derive/missing_attribute.fail.rs:15:10 --> tests/deref_mut_derive/missing_attribute_fail.rs:16:10
| |
15 | #[derive(DerefMut)] 16 | #[derive(DerefMut)]
| ^^^^^^^^ | ^^^^^^^^
| |
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -1,13 +0,0 @@
use bevy_derive::DerefMut;
#[derive(DerefMut)]
struct TupleStruct(usize, #[deref] String);
#[derive(DerefMut)]
struct Struct {
foo: usize,
#[deref]
bar: String,
}
fn main() {}

View file

@ -1,33 +0,0 @@
error[E0277]: the trait bound `TupleStruct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref.fail.rs:4:8
|
4 | struct TupleStruct(usize, #[deref] String);
| ^^^^^^^^^^^ the trait `Deref` is not implemented for `TupleStruct`
|
note: required by a bound in `DerefMut`
--> $RUST/core/src/ops/deref.rs
error[E0277]: the trait bound `TupleStruct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref.fail.rs:3:10
|
3 | #[derive(DerefMut)]
| ^^^^^^^^ the trait `Deref` is not implemented for `TupleStruct`
|
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `Struct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref.fail.rs:7:8
|
7 | struct Struct {
| ^^^^^^ the trait `Deref` is not implemented for `Struct`
|
note: required by a bound in `DerefMut`
--> $RUST/core/src/ops/deref.rs
error[E0277]: the trait bound `Struct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref.fail.rs:6:10
|
6 | #[derive(DerefMut)]
| ^^^^^^^^ the trait `Deref` is not implemented for `Struct`
|
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -0,0 +1,19 @@
// I'd love to check for E0277 errors here but we can't because
// the diagnostic contains a path to the system libraries which
// isn't consistent across systems.
use bevy_derive::DerefMut;
#[derive(DerefMut)]
//~^ ERROR: trait bound
struct TupleStruct(usize, #[deref] String);
//~^ ERROR: trait bound
#[derive(DerefMut)]
//~^ ERROR: trait bound
struct Struct {
//~^ ERROR: trait bound
foo: usize,
#[deref]
bar: String,
}

View file

@ -0,0 +1,43 @@
error[E0277]: the trait bound `TupleStruct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref_fail.rs:10:8
|
10 | struct TupleStruct(usize, #[deref] String);
| ^^^^^^^^^^^ the trait `Deref` is not implemented for `TupleStruct`
|
note: required by a bound in `DerefMut`
--> $RUSTUP_HOME/.rustup/toolchains/stable-x86_64-pc-windows-msvc/lib/rustlib/src/rust/library/core/src/ops/deref.rs:264:21
|
264 | pub trait DerefMut: Deref {
| ^^^^^ required by this bound in `DerefMut`
error[E0277]: the trait bound `TupleStruct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref_fail.rs:7:10
|
7 | #[derive(DerefMut)]
| ^^^^^^^^ the trait `Deref` is not implemented for `TupleStruct`
|
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `Struct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref_fail.rs:15:8
|
15 | struct Struct {
| ^^^^^^ the trait `Deref` is not implemented for `Struct`
|
note: required by a bound in `DerefMut`
--> $RUSTUP_HOME/.rustup/toolchains/stable-x86_64-pc-windows-msvc/lib/rustlib/src/rust/library/core/src/ops/deref.rs:264:21
|
264 | pub trait DerefMut: Deref {
| ^^^^^ required by this bound in `DerefMut`
error[E0277]: the trait bound `Struct: Deref` is not satisfied
--> tests/deref_mut_derive/missing_deref_fail.rs:13:10
|
13 | #[derive(DerefMut)]
| ^^^^^^^^ the trait `Deref` is not implemented for `Struct`
|
= note: this error originates in the derive macro `DerefMut` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,11 +0,0 @@
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_mut_derive/multiple_attributes.fail.rs:5:36
|
5 | struct TupleStruct(#[deref] usize, #[deref] String);
| ^^^^^^^^
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_mut_derive/multiple_attributes.fail.rs:19:5
|
19 | #[deref]
| ^^^^^^^^

View file

@ -2,7 +2,11 @@ use bevy_derive::DerefMut;
use std::ops::Deref; use std::ops::Deref;
#[derive(DerefMut)] #[derive(DerefMut)]
struct TupleStruct(#[deref] usize, #[deref] String); struct TupleStruct(
#[deref] usize,
#[deref] String
//~^ ERROR: can only be used on a single field
);
impl Deref for TupleStruct { impl Deref for TupleStruct {
type Target = String; type Target = String;
@ -17,6 +21,7 @@ struct Struct {
#[deref] #[deref]
foo: usize, foo: usize,
#[deref] #[deref]
//~^ ERROR: can only be used on a single field
bar: String, bar: String,
} }
@ -27,5 +32,3 @@ impl Deref for Struct {
&self.bar &self.bar
} }
} }
fn main() {}

View file

@ -0,0 +1,14 @@
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_mut_derive/multiple_attributes_fail.rs:7:5
|
7 | #[deref] String
| ^^^^^^^^
error: `#[deref]` attribute can only be used on a single field
--> tests/deref_mut_derive/multiple_attributes_fail.rs:23:5
|
23 | #[deref]
| ^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -1,8 +1,11 @@
//@check-pass
use bevy_derive::DerefMut; use bevy_derive::DerefMut;
use std::ops::Deref; use std::ops::Deref;
#[derive(DerefMut)] #[derive(DerefMut)]
struct TupleStruct(usize, #[deref] String); // The first field is never read, but we want it there to check that the derive skips it.
struct TupleStruct(#[allow(dead_code)] usize, #[deref] String);
impl Deref for TupleStruct { impl Deref for TupleStruct {
type Target = String; type Target = String;
@ -14,6 +17,8 @@ impl Deref for TupleStruct {
#[derive(DerefMut)] #[derive(DerefMut)]
struct Struct { struct Struct {
#[allow(dead_code)]
// Same justification as above.
foo: usize, foo: usize,
#[deref] #[deref]
bar: String, bar: String,

View file

@ -1,3 +1,4 @@
//@check-pass
use bevy_derive::DerefMut; use bevy_derive::DerefMut;
use std::ops::Deref; use std::ops::Deref;

View file

@ -0,0 +1,4 @@
fn main() -> bevy_compile_test_utils::ui_test::Result<()> {
bevy_compile_test_utils::test_multiple(["tests/deref_derive", "tests/deref_mut_derive"])
}

View file

@ -7,6 +7,13 @@ repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
publish = false publish = false
[dependencies]
# ui_test dies if we don't specify the version. See oli-obk/ui_test#211
bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev" }
[dev-dependencies] [dev-dependencies]
bevy_reflect = { path = "../bevy_reflect" } bevy_compile_test_utils = { path = "../bevy_compile_test_utils" }
trybuild = "1.0.71"
[[test]]
name = "derive"
harness = false

View file

@ -5,3 +5,5 @@ Bevy.
The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans). The tests assert on the exact compiler errors and can easily fail for new Rust versions due to updated compiler errors (e.g. changes in spans).
The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)). The `CI` workflow executes these tests on the stable rust toolchain (see [tools/ci](../../tools/ci/src/main.rs)).
For information on writing tests see [bevy_compile_test_utils/README.md](../bevy_compile_test_utils/README.md).

View file

@ -0,0 +1,3 @@
fn main() -> bevy_compile_test_utils::ui_test::Result<()> {
bevy_compile_test_utils::test("tests/reflect_derive")
}

View file

@ -1,6 +0,0 @@
#[test]
fn test() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/reflect_derive/*.fail.rs");
t.pass("tests/reflect_derive/*.pass.rs");
}

View file

@ -1,7 +1,6 @@
//@check-pass
use bevy_reflect::prelude::*; use bevy_reflect::prelude::*;
fn main() {}
#[derive(Default)] #[derive(Default)]
struct NonReflect; struct NonReflect;

View file

@ -13,10 +13,10 @@ impl<T> FromType<T> for ReflectMyTrait {
// Reason: populated `where` clause must be last with #[reflect(MyTrait)] // Reason: populated `where` clause must be last with #[reflect(MyTrait)]
#[derive(Reflect)] #[derive(Reflect)]
#[reflect(where T: std::fmt::Debug, MyTrait)] #[reflect(where T: std::fmt::Debug, MyTrait)]
//~^ ERROR: /expected.+:/
// TODO: Investigate a way to improve the error message.
pub struct Foo<T> { pub struct Foo<T> {
value: String, value: String,
#[reflect(ignore)] #[reflect(ignore)]
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
fn main() {}

View file

@ -1,5 +1,8 @@
error: expected `:` error: expected `:`
--> tests/reflect_derive/custom_where.fail.rs:15:44 --> tests/reflect_derive/custom_where_fail.rs:15:44
| |
15 | #[reflect(where T: std::fmt::Debug, MyTrait)] 15 | #[reflect(where T: std::fmt::Debug, MyTrait)]
| ^ | ^
error: aborting due to 1 previous error

View file

@ -1,3 +1,4 @@
//@check-pass
use bevy_reflect::{FromType, Reflect}; use bevy_reflect::{FromType, Reflect};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -34,5 +35,3 @@ pub struct Baz<T> {
#[reflect(ignore)] #[reflect(ignore)]
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
fn main() {}

View file

@ -4,6 +4,7 @@ use bevy_reflect::{FromReflect, Reflect};
#[derive(Reflect)] #[derive(Reflect)]
#[reflect(from_reflect = false)] #[reflect(from_reflect = false)]
#[reflect(from_reflect = true)] #[reflect(from_reflect = true)]
//~^ ERROR: already set to false
struct Foo { struct Foo {
value: String, value: String,
} }
@ -12,14 +13,14 @@ struct Foo {
#[derive(Reflect)] #[derive(Reflect)]
#[reflect(from_reflect = true)] #[reflect(from_reflect = true)]
#[reflect(from_reflect = false)] #[reflect(from_reflect = false)]
//~^ ERROR: already set to true
struct Bar { struct Bar {
value: String, value: String,
} }
// Reason: Conflicting `FromReflect` implementations // Reason: Conflicting `FromReflect` implementations
#[derive(Reflect, FromReflect)] #[derive(Reflect, FromReflect)]
//~^ ERROR: conflicting implementation
struct Baz { struct Baz {
value: String, value: String,
} }
fn main() {}

View file

@ -1,21 +1,25 @@
error: `from_reflect` already set to false error: `from_reflect` already set to false
--> tests/reflect_derive/from_reflect.fail.rs:6:26 --> tests/reflect_derive/from_reflect_fail.rs:6:26
| |
6 | #[reflect(from_reflect = true)] 6 | #[reflect(from_reflect = true)]
| ^^^^ | ^^^^
error: `from_reflect` already set to true error: `from_reflect` already set to true
--> tests/reflect_derive/from_reflect.fail.rs:14:26 --> tests/reflect_derive/from_reflect_fail.rs:15:26
| |
14 | #[reflect(from_reflect = false)] 15 | #[reflect(from_reflect = false)]
| ^^^^^ | ^^^^^
error[E0119]: conflicting implementations of trait `FromReflect` for type `Baz` error[E0119]: conflicting implementations of trait `FromReflect` for type `Baz`
--> tests/reflect_derive/from_reflect.fail.rs:20:19 --> tests/reflect_derive/from_reflect_fail.rs:22:19
| |
20 | #[derive(Reflect, FromReflect)] 22 | #[derive(Reflect, FromReflect)]
| ------- ^^^^^^^^^^^ conflicting implementation for `Baz` | ------- ^^^^^^^^^^^ conflicting implementation for `Baz`
| | | |
| first implementation here | first implementation here
| |
= note: this error originates in the derive macro `FromReflect` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `FromReflect` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0119`.

Some files were not shown because too many files have changed in this diff Show more