Questions on Enum type and IRGen equivalence

I am trying to understand compiler terminology surrounding enums. Most of my understanding comes from description found in ..\swift\lib\IRGen\GenEnum.cpp

Given the following enum declaration:

enum CompassPoint {
    case north
    case south
    case east
    case west
}

GenEnum.cpp states:

//  An abstract enum value consists of a payload portion, sized to hold the
//  largest possible payload value, and zero or more tag bits, to select
//  between cases. The payload might be zero sized, if the enum consists
//  entirely of empty cases, or there might not be any tag bits, if the
//  lowering is able to pack all of them into the payload itself.
  1. Is it fair to say that for CompassPoint enum, there are four enum values (north, south, east, west)?
  2. If so, there are also four payload portions (one for each north, south, east and west) - each of which in turn will have a zero or more tag bits to select between the cases. Therefore a payload for enum value east will contain 3 as the tag bit as it happens to be the third case?
  3. If I remove all the four cases from the CompassPoint enum like so enum CompassPoint{ } then it becomes zero sized payload?
  4. If my understanding so far is correct then what does it mean by "If the enum has a single payload case and one or more no-payload cases,"? How can this case be represented?
  5. Is the CompassPoint enum defined above considered a multi-payload enum since it has 4 cases? If I remove 3 cases from CompassPoint then it become a single-payload enum? If not, can you provide me an exaple of multiple payload enums?

Thanks so much for any insights.

The "payload" is the runtime/IRGen term for an enum case's "associated value". CompassPoint's cases have no associated values, so the generated enum will have no payload portion. By comparison, Optional is a single-payload enum (since it has only one case with an associated value, .some), and a hypothetical Either<Left, Right> would be a multi-payload enum.

Thanks @jrose. This helps a lot. I did not know about "associated value" angle of payload and had been under false assumption all this time.

Just like to take this a little further with another example:

enum Animal {
  case Dog
  case Cat
  case Bird(String)
  case Fish(String, Int)
}

So in this case we have 2 single-payloads for enum Animal (one for Bird and another for Fish - Fish is probably still considered single-payload since the only difference is number of associated values - am I right?).

This implies that IRGen's storeEnumTagSinglePayload will be called for Bird and Fish associated value enum cases. GenEnum.cpp says "GetEnumTag: Getting the current case of an enum value" -> I am not clear on what it means by "current case" of an enum value. Is it the "case number" of the enum? so for Bird case it will be 3 and Fish will be 4?

thanks.

No, that's not correct. We talk about the enum being single-payload or multi-payload, not individual cases. An enum is "single-payload" if it has one case with a payload (associated value), and "multi-payload" if more than one case has a payload. (It doesn't matter how many values are contained within the payloads.)

The tag does represent which case is stored in a particular enum value, but the actual representation is an implementation detail. So you're conceptually correct about that part, but the implementation might not actually use "3" for "Bird" and "4" for "Fish".

Thanks @jrose

Interestingly for the following no-paylaod enums, IRGen still generates store/getEnumTagSinglePayload code. I would have though otherwise. Will continue to explore :slight_smile:

enum Animal {
  case Dog
  case Cat
}