Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this enum declaration working now?

While answering another question, Jon Skeet mentioned that there is a weird thing going on with the definition of enums. His answer.

He states that redifining the underlying type of an enum is only possible with the type-aliases and not with the framework types (int is valid, Int32 not, etc.)

public enum Foo : UInt32 {} // Invalid
public enum Bar : uint   {} // Valid

Now I tried to reproduce that (with C#6/Roslyn in VS2015), and I didn't come to the same conclusion:

public enum TestEnum : UInt32
{

}

and

public enum MyEnum : uint
{

}

are both totally valid. Why is that so? Or has what changed?


EDIT:

So to clear up things, it was a change in C#6, that has not been documented yet, and it will be documented soon, as you can read from this git issue on the Roslyn Github

like image 983
Mafii Avatar asked Jan 06 '23 23:01

Mafii


1 Answers

It’s certainly odd that this is working now with C# 6. The current in-progress specification still lists the following grammar for specifying a base in enum declarations:

enum_base
    : ':' integral_type
    ;

And the integral types are defined as actual fixed tokens:

integral_type
    : 'sbyte'
    | 'byte'
    | 'short'
    | 'ushort'
    | 'int'
    | 'uint'
    | 'long'
    | 'ulong'
    | 'char'
    ;

Judging by this language specification, using some other base type that does not appear in that list of static type identifiers should be rejected by the parser and cause a syntax error.

Given that that’s not what happens, there are two possibilities: Either the parser was changed deliberately to accept the non-aliased types there, or the parser incorrectly accepts those.

If we look at the implementation of Roslyn, then we can see why this requirement in the specification is not enforced. The enum declaration parser simply does not check for it but parses any type:

BaseListSyntax baseList = null;
if (this.CurrentToken.Kind == SyntaxKind.ColonToken)
{
    var colon = this.EatToken(SyntaxKind.ColonToken);
    var type = this.ParseType(false);
    var tmpList = _pool.AllocateSeparated<BaseTypeSyntax>();
    tmpList.Add(_syntaxFactory.SimpleBaseType(type));
    baseList = _syntaxFactory.BaseList(colon, tmpList);
    _pool.Free(tmpList);
}

At this point, it does not really differ much from the code for “normal” inheritance. So any type restriction does not apply on the syntax level, but on the semantic level—at which point type alias are probably already evaluated.

So this seems to be a bug: Either in the specification, or in the parser. Given that the specification is still a work in progress, this might be fixed later.

like image 159
poke Avatar answered Jan 15 '23 11:01

poke