Skip to content

Conversation

@Yarwin
Copy link
Contributor

@Yarwin Yarwin commented Oct 18, 2025

Long story short AsArg<Option<Gd<T>> bounds were too restrictive which made it unusable with user-defined classes (despite Option<Gd<MyClass>> being totally valid).

In other words, this did not compile:

#[derive(GodotClass)]
#[class(init, base = Node)]
struct MyClass {
    base: Base<Node>
}

#[godot_api]
impl MyClass {
    #[signal]
    fn my_signal(arg: Option<Gd<MyClass>>);

    #[func]
    fn foo(&mut self) {
        let obj = self.to_gd();
        self.signals().my_signal().emit(&obj);
        let smth: Option<Gd<MyClass>> = None;
        self.signals().my_signal().emit(smth.as_ref());
    }
}
compile error
error[E0271]: type mismatch resolving `<MyClass as Bounds>::Declarer == DeclEngine`
  --> src/lib.rs:27:41
   |
27 |         self.signals().my_signal().emit(&obj);
   |                                    ---- ^^^^ type mismatch resolving `<MyClass as Bounds>::Declarer == DeclEngine`
   |                                    |
   |                                    required by a bound introduced by this call
   |
note: expected this to be `DeclEngine`
  --> src/lib.rs:8:10
   |
 8 | #[derive(GodotClass)]
   |          ^^^^^^^^^^
   = note: required for `&godot::prelude::Gd<MyClass>` to implement `AsArg<Option<godot::prelude::Gd<MyClass>>>`
note: required by a bound in `__godot_Signal_MyClass_my_signal::<'_, C>::emit`
  --> src/lib.rs:14:1
   |
14 | #[godot_api]
   | ^^^^^^^^^^^^ required by this bound in `__godot_Signal_MyClass_my_signal::<'_, C>::emit`
   = note: this error originates in the derive macro `GodotClass` which comes from the expansion of the attribute macro `godot_api` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0271]: type mismatch resolving `<MyClass as Bounds>::Declarer == DeclEngine`
  --> src/lib.rs:29:41
   |
29 |         self.signals().my_signal().emit(smth.as_ref());
   |                                    ---- ^^^^^^^^^^^^^ type mismatch resolving `<MyClass as Bounds>::Declarer == DeclEngine`
   |                                    |
   |                                    required by a bound introduced by this call
   |
note: expected this to be `DeclEngine`
  --> src/lib.rs:8:10
   |
 8 | #[derive(GodotClass)]
   |          ^^^^^^^^^^
   = note: required for `Option<&godot::prelude::Gd<MyClass>>` to implement `AsArg<Option<godot::prelude::Gd<MyClass>>>`
note: required by a bound in `__godot_Signal_MyClass_my_signal::<'_, C>::emit`
  --> src/lib.rs:14:1
   |
14 | #[godot_api]
   | ^^^^^^^^^^^^ required by this bound in `__godot_Signal_MyClass_my_signal::<'_, C>::emit`
   = note: this error originates in the derive macro `GodotClass` which comes from the expansion of the attribute macro `godot_api` (in Nightly builds, run with -Z macro-backtrace for more info)

Since it is compilation error only I covered it with doctests (I'm pretty sure doctest works because it failed on me three times due to typos and whatnot).

Gd:null_arg remains unchanged (idk what to think about it - let arg: Option<Gd<MyClass> = None; ain't that bad).


Reported by Iride Lombardi on discord (thanks!): https://discord.com/channels/723850269347283004/1429013604258025554/1429013604258025554

@Yarwin Yarwin added bug c: core Core components labels Oct 18, 2025
@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1371

Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! The logic error here was likely that base would be strictly a base class, but the Inherits bound is also implemented for the class itself.

Comment on lines 791 to 792
/// // With move:
/// self.signals().signal_optional_user_obj().emit(Some(arg).as_ref());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only tests as_ref() doing &Option<T> -> Option<&T>, which isn't godot-rust specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, testing it is silly.

Comment on lines 793 to 794
/// // With None (Note: Gd::null_arg() is restricted):
/// self.signals().signal_optional_user_obj().emit(None::<Gd<MyClass>>.as_ref());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here?

What do you mean with "restricted", could you clarify?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Limited to engine classes

@Yarwin Yarwin force-pushed the bugfix/ease-asarg-bounds branch from b094d40 to 57f4206 Compare October 19, 2025 15:16
@Yarwin Yarwin added this pull request to the merge queue Oct 19, 2025
Merged via the queue into godot-rust:master with commit 7079ec0 Oct 19, 2025
18 checks passed
@Yarwin Yarwin deleted the bugfix/ease-asarg-bounds branch October 19, 2025 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug c: core Core components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot use Option<Gd<T>> as signal argument when T is a user declared class

3 participants