bevy_lint::lints

Module borrowed_reborrowable

Source
Expand description

Checks for function parameters that take a mutable reference to a re-borrowable type.

§Motivation

Several Bevy types look like they are owned, when in reality they contain an &mut reference to the data owned by the ECS. Commands and Query are examples of such types that pretend to own data for better user ergonomics.

This can be an issue when a user writes a function that takes a mutable reference to one of these types, not realizing that it itself is already a reference. These mutable references can almost always be readily converted back to an owned instance of the type, which is a cheap operation that avoids nested references.

The only time a re-borrowable type cannot be re-borrowed is when the function returns referenced data that is bound to the mutable reference of the re-borrowable type.

§Known Issues

This lint does not currently support the Fn traits or function pointers. This means the following types will not be caught by the lint:

  • impl FnOnce(&mut Commands)
  • Box<dyn FnMut(&mut Commands)>
  • fn(&mut Commands)

§Example

fn system(mut commands: Commands) {
    helper_function(&mut commands);
}

// This takes `&mut Commands`, but it doesn't need to!
fn helper_function(commands: &mut Commands) {
    // ...
}

Use instead:

fn system(mut commands: Commands) {
    // Convert `&mut Commands` to `Commands`.
    helper_function(commands.reborrow());
}

fn helper_function(mut commands: Commands) {
    // ...
}

The following is an example where a type cannot be re-borrowed, for which this lint will not emit any warning:

fn system(mut commands: Commands) {
    let entity_commands = helper_function(&mut commands);
}

// Note how this function returns a reference with the same lifetime as `Commands`.
fn helper_function<'a>(commands: &'a mut Commands) -> EntityCommands<'a> {
    commands.spawn_empty()
}

Structs§

Statics§