diff --git a/common/changes/@typespec/compiler/fix-interface-factory-crash_2023-04-10-17-28.json b/common/changes/@typespec/compiler/fix-interface-factory-crash_2023-04-10-17-28.json new file mode 100644 index 00000000000..2a4387f7f36 --- /dev/null +++ b/common/changes/@typespec/compiler/fix-interface-factory-crash_2023-04-10-17-28.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/compiler", + "comment": "Fix: Interface with templated operation causing crash if defined after use", + "type": "none" + } + ], + "packageName": "@typespec/compiler" +} \ No newline at end of file diff --git a/packages/compiler/core/checker.ts b/packages/compiler/core/checker.ts index c5ce4176cf0..ce5a0f5e944 100644 --- a/packages/compiler/core/checker.ts +++ b/packages/compiler/core/checker.ts @@ -1083,7 +1083,11 @@ export function createChecker(program: Program): Checker { return sym.type as TemplatedType; } - return checkDeclaredType(sym, decl, mapper) as TemplatedType; + if (sym.flags & SymbolFlags.Member) { + return checkMemberSym(sym, mapper) as TemplatedType; + } else { + return checkDeclaredType(sym, decl, mapper) as TemplatedType; + } } /** diff --git a/packages/compiler/test/checker/interface.test.ts b/packages/compiler/test/checker/interface.test.ts index 7f2de3df2b3..78865d9957b 100644 --- a/packages/compiler/test/checker/interface.test.ts +++ b/packages/compiler/test/checker/interface.test.ts @@ -317,6 +317,35 @@ describe("compiler: interfaces", () => { strictEqual(returnType.name, "int32"); }); + it("can instantiate template operation inside templated interface (inverted order)", async () => { + const { Foo, bar } = (await runner.compile(` + alias Bar = MyFoo.bar; + + alias MyFoo = Foo; + + @test interface Foo { + @test bar(input: A): B; + } + `)) as { + Foo: Interface; + bar: Operation; + }; + + strictEqual(Foo.operations.size, 1); + ok( + isTemplateDeclaration(Foo.operations.get("bar")!), + "Operation inside MyFoo interface is still a template" + ); + + const input = bar.parameters.properties.get("input")!.type; + strictEqual(input.kind, "Scalar" as const); + strictEqual(input.name, "string"); + + const returnType = bar.returnType; + strictEqual(returnType.kind, "Scalar" as const); + strictEqual(returnType.name, "int32"); + }); + it("cache templated operations", async () => { const { Index } = (await runner.compile(` @test interface Foo {