fix(subscriptions): generate valid converter arms for keyword message types - #595
Conversation
… types (#593, #594) ConsumeContextConverterGenerator formatted type names with FullyQualifiedFormat, which renders keyword types as `string` / `object` without a global:: prefix, and then prepended global:: itself. The resulting `global::string` is not valid C#, so a keyword message type, or an array of one, broke the build with CS1041. Format names without UseSpecialTypes so these types are emitted by their metadata names (global::System.String). Skip `dynamic` altogether: it can be neither qualified nor used in a type pattern, so it produced `global::dynamic` (CS0400). With `object` now compiling, its arm could be ordered ahead of an interface arm and subsume it (CS8510): an interface converts to object, but object is not among its base types, so both had specificity zero. Count object for interfaces, which leaves object as the only type with no supertypes, so its arm always goes last. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
PR Summary by QodoGenerate valid converter arms for keyword message types
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1.
|
Test Results 48 files ± 0 48 suites ±0 15m 9s ⏱️ + 1m 16s Results for commit 9d35447. ± Comparison against base commit 9179885. This pull request removes 9 and adds 15 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Formatting type names without UseSpecialTypes also changes how a keyword nested in generic arguments is rendered: List<string> is now emitted as List<global::System.String>. Pin that in the keyword message type test; the case fails when the old name format is restored. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fixes #593
Fixes #594
Two related problems in
ConsumeContextConverterGenerator, fixed together because the second only becomes reachable once the first is fixed.Keyword message types (#593)
GetTypeSyntaxformatted type names withSymbolDisplayFormat.FullyQualifiedFormatand prependedglobal::when the name did not already start with it. That format includesUseSpecialTypes, so keyword types come back asstring/object, and the generator emittedglobal::string, which is not valid C#. A keyword message type, or an array of one, broke the consuming build withCS1041.Names are now formatted without
UseSpecialTypes, so these types are emitted by their metadata names:stringglobal::string(CS1041)global::System.Stringobjectglobal::object(CS1041)global::System.Objectstring[]global::string[](CS1525 and others)global::System.String[]Keywords nested in generic arguments were already fine and still are; they now render as
List<global::System.String>instead ofList<string>.dynamicis in the same family but cannot be fixed by renaming: it can be neither qualified nor used in a type pattern, and it producedglobal::dynamic(CS0400). It is now skipped, so such messages go through the existing fallback conversion. This was not in the issue; I found it while testing the keyword cases.objectarm ordered before an interface arm (#594)With
objectcompiling, its arm could be emitted ahead of an interface arm and subsume it (CS8510). The specificity rank from #592 counts base classes plus all interfaces, and an interface converts toobjectalthoughobjectis not among its base types, soobjectand an interface with no base interfaces both had rank 0 and kept discovery order.The rank now counts
objectfor interfaces. The strict ordering still holds (a class implementingIcountsobject,Iand everythingIcounts), andobjectis left as the only type with rank 0, so its arm always goes last.Tests
Added to
ConsumeContextConverterGeneratorTests, each seen failing first:Should_emit_compilable_arm_for_keyword_message_typeforstring,objectandstring[]Should_not_emit_arm_for_dynamic_message_typeShould_emit_object_after_interfaces, withobjectdiscovered before the interfaceAdded after review: a
List<string>case in the keyword test, pinning the nested renderingList<global::System.String>. It passed straight away since the fix was already in place, so I checked it by restoring the old name format, which makes it fail.Verified locally on net10.0 only (143 tests in the project pass, generator builds with no warnings, and the Mongo projection tests and the Postgres Bookings sample build against the patched generator); net8.0 and net9.0 runtimes are not installed on my machine, so those rely on CI.
No public API change, so no docs or plugin updates are needed.
🤖 Generated with Claude Code