Skip to content

Native subexpressions in bsn! can have lifetime issues #24775

Description

@ncbray

Bevy version and features

0.19.0

What you did

commands.spawn_scene(bsn! {
            ...
            Children [
                (
                    ...
                    TextFont { font: FontSourceTemplate::Handle({config.font_path.clone()}), font_size: {font_size}}
                ),
                (
                    ...
                    TextFont { font: FontSourceTemplate::Handle({config.font_path.clone()}), font_size: {font_size}}
                )
            ]
    });

Note there are two inline Rust blocks that reference the same variable, but those blocks are wrapped by an enum constructor.

What went wrong

The two references to config create a lifetime issue.

  --> src/mob.rs:16:26
   |
 7 |   pub fn spawn_mob(commands: &mut Commands, config: &Config, mob: &Mob, pos: Vec2) {
   |                                             ------  - let's call the lifetime of this reference `'1`
   |                                             |
   |                                             `config` is a reference that is only valid in the function body
...
16 |       commands.spawn_scene(bsn! {
   |  __________________________^
17 | |             #Mob
18 | |             template_value(Transform::from_translation(pos.extend(0.0)))
19 | |             Pickable
...  |
58 | |     });
   | |     ^
   | |     |
   | |_____`config` escapes the function body here
   |       argument requires that `'1` must outlive `'static`

Using cargo expand on a version of the code that creates a second copy of the path to work around lifetime issues, there's some weirdness in the generated code. The {font_size} code is hoisted to SceneScope:

                    let _expr4 = { font_size }.into();
                    ...
                    let _expr6 = { font_size }.into();

but font_path is not hoisted, and stays inline inside a closure:

                                ::bevy::scene::SceneFunction(move |_context, _scene| {
                                    ...
                                    __value
                                        .font = (FontSourceTemplate::Handle(
                                        { font_path1.clone() }.into(),
                                    ))
                                        .into();
                                    __value.font_size = _expr4;
                                }),
                            )),

This smells like a missing AST traversal in the code that hoists expressions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-BugAn unexpected or incorrect behaviorS-Needs-TriageThis issue needs to be labelled

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions