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

Auto-completion not working for Enum instances #2284

Closed
calebdw opened this issue May 29, 2023 · 7 comments · Fixed by #2290
Closed

Auto-completion not working for Enum instances #2284

calebdw opened this issue May 29, 2023 · 7 comments · Fixed by #2290

Comments

@calebdw
Copy link

calebdw commented May 29, 2023

Hello! Thanks for all the work getting traits to work in Enums!

However, I noticed that auto-completion for Enum properties and methods does not work outside of the Enum (and the auto-completion that does occur inside the Enum is incorrect). Note that Enums are stateless and therefore are unable to have properties, but all Enums have a name property and BackedEnums have a value property.

Inside the Enum, auto-completion sort of works:
image
but it's not showing properties and it is showing static methods (cases, from, etc.) which don't make sense on an Enum instance.

Outside the Enum, there's no auto-completion suggestions from the LS.
image

<?php

namespace Phpactor\Enums;

enum ScheduleType: int
{
    case ProductionDay = 1;
    case Break         = 2;
    case Unscheduled   = 3;

    public function label(): string
    {
        return match ($this) {
            self::ProductionDay => 'Production Day',
            default => $this->name,
        };
    }
}

class Test
{
    public function testing(): void
    {
        $a = ScheduleType::ProductionDay;
    }
}

Thanks!

@mamazu
Copy link
Contributor

mamazu commented May 29, 2023

I agree with the fact that enums are a little wonky in php. Technically you are right you shouldn't be able to configure non-static methods on an enum. But looks like you can in PHP so phpactor supports it. One thing to note here is that if you start the expression outside of the enum with

ScheduleType::

Then this will only suggest static methods and

ScheduleType->

will also include the non-static methods. This is thanks to php's "You can call static methods non-statically"-rule. I don't like it but phpactor implements it correctly.

eg.
image
and
image

hallo is missing because it's not static

And your second example $a = ScheduleType::ProductionDay-> returns nothing because ScheduleType::ProductionDay is an int.

If I missunderstood your point feel free to correct me.

@calebdw
Copy link
Author

calebdw commented May 29, 2023

This is thanks to php's "You can call static methods non-statically"-rule.

Ah interesting, that explains it---I wasn't too concerned about that part but just thought I'd mention it.

And your second example $a = ScheduleType::ProductionDay-> returns nothing because ScheduleType::ProductionDay is an int.

This is incorrect, ScheduleType::ProductionDay->value is an int, but ScheduleType::ProductionDay is a singleton class instance:

In PHP, Enums are a special kind of object. The Enum itself is a class, and its possible cases are all single-instance objects of that class. That means Enum cases are valid objects and may be used anywhere an object may be used, including type checks.

You can find example of using methods on enum cases in the docs

@mamazu
Copy link
Contributor

mamazu commented Jun 3, 2023

Okay, that doesn't make sense that the enum values are objects again. (But that's just php.)

Do you happen to know what type of object they are? They seem to have at least a label() and a value() function.

@calebdw
Copy link
Author

calebdw commented Jun 4, 2023

It's all in the docs...

Enums appear in many languages with a variety of different features. In PHP, Enums are a special kind of object. The Enum itself is a class, and its possible cases are all single-instance objects of that class. That means Enum cases are valid objects and may be used anywhere an object may be used, including type checks.

They're singleton instances of the Enum class. The docs also list some differences with objects:

    - Constructors and Destructors are forbidden.
    - Inheritance is not supported. Enums may not extend or be extended.
    - Static or object properties are not allowed.
    - Cloning an Enum case is not supported, as cases must be singleton instances.
    - Magic methods, except for those listed below, are disallowed.
    - Enums must always be declared before they are used.
    
    The following object functionality is available, and behaves just as it does on any other object:

    -Public, private, and protected methods.
    - Public, private, and protected static methods.
    - Public, private, and protected constants.
    - Enums may implement any number of interfaces.
    - Enums and cases may have attributes attached to them. The TARGET_CLASS target filter includes Enums themselves. The TARGET_CLASS_CONST target filter includes Enum Cases.
    - __call, __callStatic, and __invoke magic methods
    - __CLASS__ and __FUNCTION__ constants behave as normal

Note that while Enums cannot have state (i.e., properties), they do have a name property and BackedEnums have a value property.

They seem to have at least a label() and a value() function.

The label() method is something I added to the Enum for when human readable labels are necessary (like for front-end select options), they don't have a value() function

@dantleech
Copy link
Collaborator

We have a "todo" test for this:

// need better generic support here
wrAssertType('<missing>', Foo::FOO->value);

i'll check to see if this can now be implemented

@dantleech
Copy link
Collaborator

should be working now

@calebdw
Copy link
Author

calebdw commented Jun 4, 2023

Thanks!! Auto-complete is working for cases!

However, (I hate to keep bugging lol) I noticed that I am not able to go to the definition of methods called on Enum cases---to reuse the earlier example:

<?php

namespace Phpactor\Enums;

enum ScheduleType: int
{
    case ProductionDay = 1;
    case Break         = 2;
    case Unscheduled   = 3;

    public function label(): string
    {
        return match ($this) {
            self::ProductionDay => 'Production Day',
            default => $this->name,
        };
    }
}

class Test
{
    public function testing(): void
    {
        $a = ScheduleType::ProductionDay->label(); // unable to goto `label` definition here
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants