Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/http-server-csharp"
---

Fix crash when emitting interfaces that contain template operations. Template operations (e.g. `getItem<T>(): T`) within interfaces will simply be skipped when emitting the interface.
8 changes: 7 additions & 1 deletion packages/http-server-csharp/src/lib/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ export async function $onEmit(context: EmitContext<CSharpServiceEmitterOptions>)
usings: [],
};
for (const [name, operation] of iface.operations) {
if (isTemplateDeclaration(operation)) continue;
const doc = getDoc(this.emitter.getProgram(), operation);
const returnTypes: Type[] = [];
const [httpOp, _] = getHttpOperation(this.emitter.getProgram(), operation);
Expand Down Expand Up @@ -1004,7 +1005,12 @@ export async function $onEmit(context: EmitContext<CSharpServiceEmitterOptions>)
.checker.cloneType(responseType, { name: modelName });
responseType = returnedType;
}
this.emitter.emitType(responseType);
// TemplateParameter types cannot be emitted (they are unresolved template placeholders).
// Template operations are filtered in interfaceDeclarationOperations, but this guard
// prevents crashes if a TemplateParameter response type is encountered via other paths.
if (responseType.kind !== "TemplateParameter") {
this.emitter.emitType(responseType);
}

const context = this.emitter.getContext();
const result = getCSharpType(this.emitter.getProgram(), responseType, context.namespace);
Expand Down
17 changes: 17 additions & 0 deletions packages/http-server-csharp/test/generation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,23 @@ it("Handles user-defined model templates", async () => {
);
});

it("Handles template operations in interfaces without crashing", async () => {
// Regression test: interfaces with template operations should not crash with
// "Encountered type TemplateParameter which we don't know how to emit."
// Template operations (e.g. getItem<T>(): T) should be skipped during emission.
await compileAndValidateMultiple(
tester,
`
interface MyOps {
@get list(): string;
@get getItem<T>(): T;
}
`,
[["IMyOps.cs", ["interface IMyOps", "Task<string> ListAsync( );"]]],
[["IMyOps.cs", ["GetItemAsync"]]],
);
});

it("Handles void type in operations", async () => {
await compileAndValidateMultiple(
tester,
Expand Down
Loading