-
-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow #[cfg] to be used with #[godot_api] - Part 2: virtual impls #444
Allow #[cfg] to be used with #[godot_api] - Part 2: virtual impls #444
Conversation
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-444 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! Like #443, great work.
It's a shame that Rust forces us to use these tricks, but I'm amazed by what you came up with 😉
godot-macros/src/class/godot_api.rs
Outdated
match () { | ||
#(#cfg_attrs)* | ||
() => Some(#prv::ErasedRegisterFn { | ||
raw: #prv::callbacks::register_class_by_builder::<#class_name> | ||
}), | ||
_ => None, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very cool trick!
Can you add #[allow(unreachable_patterns)]
right here? The more local, the better -- otherwise we may accidentally swallow legitimate warnings in unrelated code.
Also, does clippy not complain if the #[cfg]
evaluates to false and the remaining code becomes
match () {
_ => None,
}
Or maybe even without that, having a match ()
which can only have one value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very cool trick!
Thanks!
Can you add
#[allow(unreachable_patterns)]
right here? The more local, the better -- otherwise we may accidentally swallow legitimate warnings in unrelated code.
Unfortunately, since the match
is being used as an expression, we can't due to rust-lang/rust#15701 (currently results in an error). Adding macros above match arms does compile, but for this purpose is useless as #[allow(...)]
over a single match arm doesn't dismiss any related warnings.
Also, does clippy not complain if the
#[cfg]
evaluates to false and the remaining code becomesmatch () { _ => None, }
Great catch:
warning: this match could be replaced by its scrutinee and body
--> examples/dodge-the-creeps/rust/src/main_scene.rs:103:31
|
103 | let _x: Option<i32> = match () {
| _______________________________^
104 | | _ => None,
105 | | };
| |_________^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
= note: `#[warn(clippy::match_single_binding)]` on by default
help: consider using the scrutinee and body instead
|
103 ~ let _x: Option<i32> = ();
104 ~ None;
|
I've added #[allow(clippy::match_single_binding)]
as well now.
Or maybe even without that, having a
match ()
which can only have one value?
That doesn't seem to generate a warning by itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! You now have this:
#[allow(unreachable_patterns)] // due to the cfg-based match statements
#[allow(clippy::match_single_binding)] // avoid warning on single-arm matches
Could you clarify the 2 comments slightly? e.g. the 2nd could be "For #[cfg(false)], match contains only single arm".
Also nitpicking, but we try to use capitalization and full stops for comments, even if they're not prose (not 100% consistent though) 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've tried to improve the comments a bit; feel free to suggest further changes.
Also, I managed to move the allow
s to the match
itself by placing the match inside a block, as showcased below:
fn main() {
let x = {
#[allow(unreachable_patterns)]
#[allow(clippy::match_single_binding)]
match () {
() => true,
_ => false,
}
};
// ^instead of let x = match () { ... }
println!("x = {x}");
}
I'm not sure why this works - seems to work even with something as simple as just 5i32
, so perhaps it's some form of workaround for the aforementioned Rust compiler issue. The sample above (on my limited local tests) seems to compile with Rust 1.69.0 as well, so this shouldn't raise MSRV.
|
||
#[cfg(any())] | ||
fn to_string(&self) -> GodotString { | ||
"Removed by #[cfg]".into() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also be panic!
, in case it's ever compiled in and called?
Or maybe even compile_error!
, if that works here? (Similar thoughs apply below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea, done!
ce6a756
to
c0dac5f
Compare
Hmmm, CI's runtime tests just made me notice a bug - it seems that specifying I think I can fix this for all methods by adding more match arms (one for each time the method is declared). Edit: Yep, that worked! We now have something like match () {
#[cfg(...)]
() => Some(create::<thing>),
#[cfg(...)]
() => Some(create::<thing>),
#[cfg(...)]
() => Some(create::<thing>),
_ => None,
} one arm for each implementation of the same method. This guarantees the generated FFI glue will be kept if at least one of the implementations 'survives'. (If more than one 'survives', then Rust should generate an error anyway.) I'll probably try to add some more runtime tests over the next few days. Though CI is still failing in one check which seems to be unrelated to this PR. |
37e7e6a
to
a9b9b67
Compare
Oh nice, great improvements! Yes, the CI is an epic maintenance chore lately. I don't know if it's due to upstream breakages or other changes, but this is now the 3rd problem within a week or so:
|
a9b9b67
to
5b99137
Compare
5b99137
to
8c63cc0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
@Bromeon thanks!! Btw, do you think this deserved some runtime tests like in #443 ? Before the merge, I was thinking of adding something using class_has_method, but I wasn't sure if that would properly check virtual methods... Unless the no inheritance thing would be enough to check whether or not we have overridden something? |
Related to (but can be merged independently of) #443. Fixes #399.
Note: Turns out this PR was smaller than I expected, so both PRs could theoretically be fused together; however, this particular PR should be faster to review (/has less design decisions).
Explicitly allows
#[cfg]
to be used above methods in virtual#[godot_api]
impls, following solution 1 from #379 (comment).It does this by just transporting the
#[cfg]
attrs to the virtual methods' generated FFI glue, thus avoiding their registration in Godot if the original method implementation was conditionally removed from compilation.Implementation details
I had to "cheat" a bit when an expression was being generated, replacing a generated e.g.
Some(create::<thing>)
with
This could have been done with
But that would leave us vulnerable to a certain warning regarding shadowed labels (if an outer block also used 'blk for some reason), and that warning doesn't seem to be dismissible/
#[allow(...)]
-able at all (this related issue rust-lang/rust#31745 was closed, but doesn't seem to have been entirely fixed...?).The
match
counterpart only requires#[allow(unreachable_patterns)]
(which I added to the generated code) to avoid warnings regarding when both patterns are present.Tests
Added some basic tests in
itest
which test compilation, but suggestions for runtime checks on the tests are appreciated (e.g. something that checks ClassDB or similar), as most of the errors related to the old behavior of#[cfg]
usage on virtual methods here would occur on runtime.One immediate result from the current
itest
block is that e.g. this:currently fails to compile as the trait does not have that method, but compiles fine after this PR.