Crystal: Question method on member with value 0 in enum with flags attribute broken

Created on 2 Jan 2019  路  7Comments  路  Source: crystal-lang/crystal

Code:

@[Flags]
enum Animal
  UNKNOWN = 0
  DOG
  CAT
  LAMA
end

pp Animal::UNKNOWN.unknown? # => false

https://play.crystal-lang.org/#/r/5wi8

bug stdlib

All 7 comments

Why do you use @[Flags]?

@j8r This is just an example.
I came across it when I wanted to rename "None" to something else.
Ideally, a None member should only be created if there is no other member with a value of 0 and the member with a value of 0 should get the right question method using #== instead of #includes?.

Currently only the None member gets the right question method defined through define_enum_none_question_method.
https://github.com/crystal-lang/crystal/blob/5502b00c9482b20ed872ea0583a5fe90d91b1e84/src/compiler/crystal/semantic/top_level_visitor.cr#L698

And another effect of having None member always defined is this:
```crystal
pp Animal::UNKNOWN # => None

Fun fact, a None member is only created if there is no one.
https://github.com/crystal-lang/crystal/blob/5502b00c9482b20ed872ea0583a5fe90d91b1e84/src/compiler/crystal/semantic/top_level_visitor.cr#L585-L591

But this means if I define a None = 0 member, no functioning question method is created.

@[Flags]
enum Animal
  None = 0
  DOG
  CAT
  LAMA
end

pp Animal::None.none? # => false

https://play.crystal-lang.org/#/r/5wjq

I still think we should remove the autogenerated None and All enum members.

Whether we keep them or not, does not change the fact that we need to define the right question method for a member with a value of 0.

@petoem It's failing right now because there's special logic in Enum#includes? and Enum#each to deal with None and All. If we remove those generated enum members the issue will be trivially fixed.

Yeah, for example replacing this ...
https://github.com/crystal-lang/crystal/blob/fcfb8f71db6c49254f821e7346797b5499af8173/src/compiler/crystal/semantic/top_level_visitor.cr#L663
with this ...

if is_flags && counter == 0
  define_enum_question_method(enum_type, member, false)
else
  define_enum_question_method(enum_type, member, is_flags)
end

... should define the correct question method.

Was this page helpful?
0 / 5 - 0 ratings