Skip to content

Fix generated error constructors and constraint attributes using the wrong C# types - #11600

Draft
Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:hsc/single-scalar-map
Draft

Fix generated error constructors and constraint attributes using the wrong C# types#11600
Timothee Guerin (timotheeguerin) wants to merge 5 commits into
microsoft:mainfrom
timotheeguerin:hsc/single-scalar-map

Conversation

@timotheeguerin

Copy link
Copy Markdown
Member

The emitter had three separate TypeSpec-scalar-to-C#-type-name maps, and they disagreed. Properties were rendered from one, error-model constructor parameters from another, and constraint attribute type arguments from a third — so the generated code did not compile:

@error model ValidationError {
  occurredAt: utcDateTime;
  docs: url;
  severity: int8;
}
  public partial class ValidationError : HttpServiceException
  {
      public required DateTimeOffset OccurredAt { get; set; }
      public required string Docs { get; set; }
      public required SByte Severity { get; set; }

-     public ValidationError(DateTimeOffset occurredAt, Uri docs, sbyte severity)
+     public ValidationError(DateTimeOffset occurredAt, string docs, SByte severity)

NumericConstraint<T> had the same problem — the attribute was instantiated with a different type than the property it annotated, so it failed to bind.

The three maps collapse into one scalar-overrides.ts that layers the emitter's deliberate divergences (plainDate/plainTimeDateTime, urlstring, safeintlong, CLR names for sized integers) over the emitter framework defaults. Anywhere a C# type name is needed outside a rendering context now goes through it, so it cannot drift from what TypeExpression renders again.


Part of a 7-PR stack moving @typespec/http-server-csharp onto the emitter framework. Stacked on #11599 — only the last commit is new here.

Adds handling for Tuple, StringTemplate, EnumMember, ModelProperty, UnionVariant,
template parameters and the full Intrinsic set. An unsupported type now reports a
diagnostic and falls back to `object` instead of throwing.

Also fixes the C# components reporting a TypeScript diagnostic for unsupported
scalars, and corrects the C# expressions emitted for the `null` and `never`
intrinsics. Adds an `isCSharpValueType` util.
…al_ComponentOverrides

The `declaration` descriptor existed but nothing dispatched to it, so an emitter
could override how a type is referenced but not how it is declared. The C#
`ClassDeclaration`, `Property` and `EnumDeclaration` now render through the
override point.
ClassDeclaration takes an explicit property list and extra members, Property
takes the full Alloy property prop set plus name/csharpType overrides,
EnumDeclaration takes an explicit member list and jsonAttributes, and
JsonConverter takes doc, access modifiers, extra members and an explicit
csharpType.
…xt.Json symbols

Deletes the emitter's own C# keyword table and its re-declaration of the
System.Text.Json.Serialization attributes, both of which are provided by
@alloy-js/csharp. Namespace segments colliding with BCL type names are still
renamed, now via a dedicated getCSharpNamespaceName helper.
…ource of truth

The emitter had three disagreeing scalar-to-C# name maps, so error model
constructors declared parameters such as DateOnly, Uri and sbyte while the
matching properties were DateTime, string and SByte - code that does not
compile. NumericConstraintAttribute<T> had the same mismatch.
@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/emitter-framework@11600
npm i https://pkg.pr.new/@typespec/http-server-csharp@11600

commit: c73ec36

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/emitter-framework
  • @typespec/http-server-csharp
Show changes

@typespec/emitter-framework - feature ✏️

Let emitters author the C# declaration components instead of forking them,> ,> - ClassDeclaration accepts an explicit properties list and extra members as children.,> - Property accepts every Alloy property prop, plus name and csharpType overrides.,> - EnumDeclaration accepts an explicit members list and a jsonAttributes prop.,> - JsonConverter accepts doc, access modifiers, extra members, an explicit csharpType, and a readReturns override.,> ,> tsx,> <ClassDeclaration type={model} properties={model.properties.values().filter(isVisible)} partial>,> <Constructor />,> </ClassDeclaration>,>

@typespec/emitter-framework - fix ✏️

Make the C# TypeExpression handle every type kind instead of throwing,> ,> Tuple, StringTemplate, EnumMember, ModelProperty, UnionVariant, template parameters and the full Intrinsic set are now supported, and an unsupported type reports a diagnostic and falls back to object rather than throwing. Also fixes the C# components reporting a TypeScript diagnostic for unsupported scalars, and corrects the C# expressions for the null and never intrinsics.

@typespec/emitter-framework - feature ✏️

Support declaration overrides in Experimental_ComponentOverrides,> ,> Only reference overrides were dispatched, so an emitter could customize how a type is referenced but not how it is declared, forcing it to fork the framework's declaration components. The C# ClassDeclaration, Property and EnumDeclaration now render through the override point.,> ,> tsx,> const overrides = Experimental_ComponentOverridesConfig().forTypeKind("ModelProperty", {,> declaration: (props) =>,> props.type.name === "id" ? (,> <props.Declaration {...props.declarationProps} name="Identifier" />,> ) : (,> props.default,> ),,> });,>

@typespec/http-server-csharp - internal ✏️

Use Alloy's C# keyword handling and System.Text.Json symbols instead of local copies,> ,> Deletes the emitter's own 217-line C# keyword table and its re-declaration of the System.Text.Json.Serialization attributes, which are both provided by @alloy-js/csharp. Namespace segments that collide with common BCL type names are still renamed, now in a dedicated getCSharpNamespaceName helper.

@typespec/http-server-csharp - fix ✏️

Fix generated error model constructors and numeric constraint attributes using the wrong C# types,> ,> Error model constructors declared parameters such as DateOnly, Uri and sbyte while the matching properties were DateTime, string and SByte, producing code that did not compile. NumericConstraintAttribute<T> had the same mismatch, which stopped the converter from binding.

@azure-sdk-automation

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

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

Labels

emitter-framework Issues for the emitter framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant