Why do I get "type has no typeinfo" error with an enum type

Type information is not supported for enums where specific ordinal values are assigned that result in enum members having ordinal values that are different to those that would normally be assigned by the compiler.

If specific values are essential or desirable, "unused" enum members will have to be inserted to "pad" the enum as required. e.g (additional indentation for emphasis only):

  type
    TMyEnum = (
                meNOTUSED1,   {= 0}
               meFirstValue,  {= 1} 
               meSecondValue,
               meThirdValue
              );

A subrange can then be used to "filter" out the unused initial value:

   TValidMyEnum = meFirstValue..meThirdValue;

Although you might then wish to consider renaming the original enum type so that your subrange type may be used throughout your project.

A subrange isn't sufficient if the enum contains "gaps":

  type
    TMyEnum = (
                meNOTUSED1,   {= 0}
               meFirstValue,  {= 1} 
               meSecondValue,
               meThirdValue,
                meNOTUSED2,
               meFinalValue   {= 5}
              );

In this case there is no simply way to extend compile-time range checking to exclude the unused members, but a couple of set types will simplify the business of implementing any necessary runtime checks:

  type
    TMyEnums = set of TMyEnum;

  const
    meNOTUSED      = [meUNUSED1, meUNUSED2]; //  .. etc as required
    meValidValues  = [Low(TMyEnum)..High(TMyEnum)] - meNOTUSED;


  if NOT (aValue in meValidValues) then
     // etc

When you want to convert enums into specific values (and back) I useally create an array const, with the desired values per enum value:

Const MyEnumValues: array[TMyEnum] of integer = (1,2,5);

This way when the enum gets expanded you get an compiler error stating you are missing an array value.

Please note when changing the order of the enums, you must change the values accordingly.

To get the ‘value’ for an enum values just write:

Value := MyEnumValues[myenum];

And to get the enum value based on the ‘value’ just loop though the values of MyEnumValues:

Function GetEnumByValue(value:integer): TMyEnum;
Var
  myenum: TMyEnum;
Begin
  For myenum = low(TMyEnum) to high(TMyEnum) do
    If MyEnumValues[myenum] = value then
      exit(myenum);
  Raise exception.create(‘invalid value for tmyenum’);
End;

Discontiguous enumerations, and enumerations which don't start at zero, don't have typeinfo. For typeinfo to be implemented, it would need to be in a different format from the existing tkEnumeration, owing to backward compatibility issues.

I considered implementing a tkDiscontiguousEnumeration (or possibly better named member) for Delphi 2010, but the benefit seemed small considering their relative scarcity and the difficulties in enumeration - how do you encode the ranges efficiently? Some encodings are better for some scenarios, worse for others.