Skip to content

ConsumeContextConverterGenerator emits invalid code for keyword message types (global::string, CS1041) #593

Description

@alexeyzimarev

Describe the bug
ConsumeContextConverterGenerator emits invalid C# when a message type is a C# keyword type (string, object) or an array of one (string[]). The consuming project fails to build with syntax errors in MessageConsumeContext_Converters.g.cs.

GetTypeSyntax, L161–L162 formats the type with SymbolDisplayFormat.FullyQualifiedFormat and then prepends global:: when the name does not already start with it. That format includes UseSpecialTypes, so keyword types come back as string / object with no global:: prefix, and the generator produces global::string, which is not valid C#.

To Reproduce

  1. Reference a keyword type as a message type anywhere the generator scans, for example:
    public static void Handle(IMessageConsumeContext<string> ctx) { }
  2. dotnet build
  3. The generated converter contains
    global::string => new MessageConsumeContext<global::string>(context),
    and the build fails with CS1041: Identifier expected; 'string' is a keyword (plus follow-on CS1001 / CS1003).

Verified by running the generator through CSharpGeneratorDriver against dev at 9179885:

Message type Generated arm Result
string global::string CS1041
object global::object CS1041
string[] global::string[] CS1525, CS8504 and others
List<string> global::System.Collections.Generic.List<string> compiles

So only top-level keyword types and arrays of them are affected; a keyword nested in generic arguments is fine.

Expected behavior
The generated converter compiles for any reference type that satisfies IMessageConsumeContext<T>'s class constraint.

A fix that I checked with the same driver setup: format without UseSpecialTypes, so keyword types are emitted by their metadata names.

static readonly SymbolDisplayFormat TypeFormat = SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(
    SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & ~SymbolDisplayMiscellaneousOptions.UseSpecialTypes
);

With that, the four cases above generate global::System.String, global::System.Object, global::System.String[] and global::System.Collections.Generic.List<global::System.String>, and all compile. The StartsWith("global::") fallback then becomes unnecessary for these types.

Additional context
Found while working on #589 / #592; it predates that change. Keyword message types are unusual, so this is low priority, but the failure is a hard build break with an error pointing at generated code.

Fixing this makes a second, currently masked problem reachable: an object arm can be ordered ahead of an interface arm. That is tracked separately and is best fixed in the same change.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions