Skip to content
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

GDScript enum fixes & refactor #69590

Merged
merged 1 commit into from
Jan 9, 2023
Merged

Conversation

anvilfolk
Copy link
Contributor

@anvilfolk anvilfolk commented Dec 5, 2022

This PR fixes a bunch of issues with enums. Also, 80% of it is unit tests ;)

Needs #71028 before it passes tests :)

At a glance

And yes, maybe I did name a lot of these "fixes" instead of "implements" because we are in feature freeze ;)

Fixes & features

It does a general refactor of how enums are handled internally and in GDScript, cleaning up the code & making it slightly more consistent across GDScript enums and native enums. It also aims to unify warnings&errors between in-editor, runtime, and export debug/release templates (native enum behavior on release templates now working due to #64253).

For native enums, e.g. with TileSet, you can now use TileSet.TILE_SHAPE_SQUARE or TileSet.TileShape.TILE_SHAPE_SQUARE, and a warning will be issued if the native type does not have an accessed property.

Typing with enums now works properly for variables, function parameters and function returns, and comprehensive unit tests have been added to check this. Example which is now possible, and will throw errors if the wrong enum is used.

class_name OuterClass

enum MyEnum {V0, V1}

class InnerClass:
  enum MyEnum {V0, V1}

func outer_inner_class_class(e : InnerClass.MyEnum) -> Outer.InnerClass.MyEnum:
  print(e)
  return e

func _ready()
  var boom :  = outer_inner_class_class(V1)
  var good :  = outer_inner_class_class(OuterClass.InnerClass.V1)

@Chaosus Chaosus modified the milestones: 4.0, 4.x Dec 5, 2022
@anvilfolk anvilfolk force-pushed the enums branch 6 times, most recently from 62043d3 to 4db278c Compare December 6, 2022 04:45
@anvilfolk anvilfolk changed the title GDScript enum refactor GDScript enum fixes & refactor Dec 6, 2022
@anvilfolk anvilfolk force-pushed the enums branch 3 times, most recently from 7e850d4 to bfa54c1 Compare December 7, 2022 00:08
Copy link
Contributor

@rune-scape rune-scape left a comment

Choose a reason for hiding this comment

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

i know it's still a draft, but this looks great! nice job refactoring :)

modules/gdscript/gdscript_analyzer.cpp Outdated Show resolved Hide resolved
modules/gdscript/gdscript_analyzer.cpp Outdated Show resolved Hide resolved
modules/gdscript/gdscript_analyzer.cpp Outdated Show resolved Hide resolved
modules/gdscript/gdscript_analyzer.cpp Outdated Show resolved Hide resolved
@rune-scape
Copy link
Contributor

rune-scape commented Dec 7, 2022

what happens with this script?:

enum E1 {V0, V1}
enum E2 {V1, V0}

func _ready():
    print(V0, V1)

it doesn't look like the values are added as members, or checked for name conflicts,
i thought the way to use enum values at a class level was to do:

enum {
    V0,
    V1
}

@anvilfolk anvilfolk marked this pull request as ready for review December 7, 2022 01:01
@anvilfolk anvilfolk requested a review from a team as a code owner December 7, 2022 01:01
@anvilfolk
Copy link
Contributor Author

Oooooh, excellent comments, thanks @rune-scape! I am done for the day, but will think & tackle these when I can! I've implemented everything I wanted for this PR, so your comments are super timely :)

@anvilfolk
Copy link
Contributor Author

anvilfolk commented Dec 7, 2022

what happens with this script?:

That's a really cool one!

I tried keeping things consistent & backwards compatible. Firstly, for native classes, NativeClass.EnumName.ENUM_VALUE wasn't possible, only NativeClass.ENUM_VALUE. On the other hand, GDScript was the opposite, with GDScriptClass.NAMED_ENUM_VALUE not working, only NamedEnum.NAMED_ENUM_VALUE.

So the two behaviors existed but were used inconsistently between native & gdscript types. I figured the only way to move forward without breaking existing code was to allow both types of access to both types of enums.

Good thought on maybe using Member to represent named enum values. I thought about it briefly, but I believe we would lose type information if we created ENUM_VALUE members from ENUM values, and would've had to check which enum it belonged to. I'm tempted to just add checking named enums wherever appropriate once I factor that out into a function.

But now you're right, it creates issues with shadowing that need some work. GDScript seems pretty lenient on allowing shadowing with warnings rather than errors, so I'm tempted to implement this:

  1. Unnamed enum values shadow named enum values, since named enums can be accessed by adding enum name qualifiers.
  2. Local enum values, unnamed & named, will shadow base_class & outer_class enum values of any kind, since "upper" enums can be accessed by adding class qualifiers.

I'm tempted to either not add any warnings at all, or to add warnings to 2 only, since it might be less obvious that you are doing it.

@anvilfolk anvilfolk force-pushed the enums branch 3 times, most recently from c50429e to 5652856 Compare December 8, 2022 04:22
@anvilfolk
Copy link
Contributor Author

I actually realized that I should be able to use reduce_identifier_from_base to find named enum values, rather than using my auxiliary methods.

So that + adding shadow warnings are on my list, but hopefully that's it?

@anvilfolk anvilfolk force-pushed the enums branch 2 times, most recently from 2030e9c to a6c0894 Compare December 9, 2022 05:15
@anvilfolk
Copy link
Contributor Author

anvilfolk commented Dec 9, 2022

Alright, I think this PR is done :)

There's some issues with shadowing outer class members that needs work in check_class_member_name_conflict but I think that's a different PR.

@anvilfolk anvilfolk force-pushed the enums branch 9 times, most recently from 0ea2876 to 864372e Compare January 9, 2023 12:52
modules/gdscript/gdscript_analyzer.cpp Show resolved Hide resolved
modules/gdscript/gdscript_analyzer.cpp Outdated Show resolved Hide resolved
modules/gdscript/gdscript_analyzer.cpp Show resolved Hide resolved
modules/gdscript/gdscript_parser.cpp Outdated Show resolved Hide resolved
@anvilfolk anvilfolk force-pushed the enums branch 2 times, most recently from 3032ba8 to a5004f6 Compare January 9, 2023 14:01
@Maran23
Copy link
Contributor

Maran23 commented Jan 9, 2023

This may fixes #70915 as well. Can you verify that? :)

@anvilfolk
Copy link
Contributor Author

It actually does - I confirmed the bug is still there on Beta 10, but doesn't happen in this PR :) Thanks for linking!

@Maran23
Copy link
Contributor

Maran23 commented Jan 9, 2023

It actually does - I confirmed the bug is still there on Beta 10, but doesn't happen in this PR :) Thanks for linking!

Glad to her!
Not sure if it works, but is it possible to add the buggy example in the ticket as test here?

@anvilfolk
Copy link
Contributor Author

Not sure if it works, but is it possible to add the buggy example in the ticket as test here?

Not with the current test framework as far as I can tell. Currently it just attempts to parse scripts. The most you can do is preload, but I don't think there's a scene tree we can use. Maybe I'm wrong though :)

Copy link
Member

@vnen vnen left a comment

Choose a reason for hiding this comment

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

Looks okay to me.

@akien-mga akien-mga merged commit 509da86 into godotengine:master Jan 9, 2023
@akien-mga
Copy link
Member

Thanks! Outstanding work 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment