From 6b028d3b3520fe27185b47de2a86d1fce21ae2e9 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 28 Feb 2024 16:42:42 -0800 Subject: [PATCH 1/6] . --- packages/compiler/src/lib/decorators.ts | 18 +++++++++++++++--- .../test/decorators/decorators.test.ts | 7 +++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/lib/decorators.ts b/packages/compiler/src/lib/decorators.ts index baa0b680c89..12b40f7b097 100644 --- a/packages/compiler/src/lib/decorators.ts +++ b/packages/compiler/src/lib/decorators.ts @@ -350,16 +350,28 @@ const errorKey = createStateSymbol("error"); /** * `@error` decorator marks a model as an error type. - * - * `@error` can only be specified on a model. + * Any derived models (using extends) will also be seen as error types. */ export function $error(context: DecoratorContext, entity: Model) { validateDecoratorUniqueOnNode(context, entity, $error); context.program.stateSet(errorKey).add(entity); } +/** + * Check if the type is an error model or a descendant of an error model. + */ export function isErrorModel(program: Program, target: Type): boolean { - return program.stateSet(errorKey).has(target); + if (target.kind !== "Model") { + return false; + } + let current: Model | undefined = target; + while (current) { + if (program.stateSet(errorKey).has(current)) { + return true; + } + current = target.baseModel; + } + return false; } // -- @format decorator --------------------- diff --git a/packages/compiler/test/decorators/decorators.test.ts b/packages/compiler/test/decorators/decorators.test.ts index 8cb9d89ac9a..95c622f1d30 100644 --- a/packages/compiler/test/decorators/decorators.test.ts +++ b/packages/compiler/test/decorators/decorators.test.ts @@ -386,6 +386,13 @@ describe("compiler: built-in decorators", () => { `); ok(isErrorModel(runner.program, A), "isError should be true"); }); + it("applies @error on derived models", async () => { + const { B } = await runner.compile(` + @error model A { } + @test model B { } + `); + ok(isErrorModel(runner.program, B), "isError should be true"); + }); it("emit diagnostic if error is not applied to a model", async () => { const diagnostics = await runner.diagnose(` From 9a0e4319eb4f8495fcd0b069f2d7380dcd312d09 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 28 Feb 2024 16:45:55 -0800 Subject: [PATCH 2/6] Create is-error-model-2024-1-29-0-44-17.md --- .chronus/changes/is-error-model-2024-1-29-0-44-17.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/is-error-model-2024-1-29-0-44-17.md diff --git a/.chronus/changes/is-error-model-2024-1-29-0-44-17.md b/.chronus/changes/is-error-model-2024-1-29-0-44-17.md new file mode 100644 index 00000000000..23ac239f745 --- /dev/null +++ b/.chronus/changes/is-error-model-2024-1-29-0-44-17.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: feature +packages: + - "@typespec/compiler" +--- + +`@error` mark model and its derived types From a012e916c490a28685f4733b8f9514b9b378078a Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 28 Feb 2024 16:47:14 -0800 Subject: [PATCH 3/6] Update .chronus/changes/is-error-model-2024-1-29-0-44-17.md --- .chronus/changes/is-error-model-2024-1-29-0-44-17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chronus/changes/is-error-model-2024-1-29-0-44-17.md b/.chronus/changes/is-error-model-2024-1-29-0-44-17.md index 23ac239f745..9ba3ef2faa2 100644 --- a/.chronus/changes/is-error-model-2024-1-29-0-44-17.md +++ b/.chronus/changes/is-error-model-2024-1-29-0-44-17.md @@ -5,4 +5,4 @@ packages: - "@typespec/compiler" --- -`@error` mark model and its derived types +Any subtype of an error(marked with `@error`) is now an error. From adae1acc7c9e26156e042972a384885e8ec0aecc Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 28 Feb 2024 16:47:52 -0800 Subject: [PATCH 4/6] fix --- packages/compiler/test/decorators/decorators.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/decorators/decorators.test.ts b/packages/compiler/test/decorators/decorators.test.ts index 95c622f1d30..c080bdc4f29 100644 --- a/packages/compiler/test/decorators/decorators.test.ts +++ b/packages/compiler/test/decorators/decorators.test.ts @@ -386,10 +386,11 @@ describe("compiler: built-in decorators", () => { `); ok(isErrorModel(runner.program, A), "isError should be true"); }); + it("applies @error on derived models", async () => { const { B } = await runner.compile(` @error model A { } - @test model B { } + @test model B extends A { } `); ok(isErrorModel(runner.program, B), "isError should be true"); }); From dc6a3d8faf445a8a352056646a29776ba8ab3eb0 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 29 Feb 2024 11:52:38 -0800 Subject: [PATCH 5/6] fix --- packages/compiler/src/lib/decorators.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler/src/lib/decorators.ts b/packages/compiler/src/lib/decorators.ts index 12b40f7b097..29866cd0335 100644 --- a/packages/compiler/src/lib/decorators.ts +++ b/packages/compiler/src/lib/decorators.ts @@ -369,7 +369,7 @@ export function isErrorModel(program: Program, target: Type): boolean { if (program.stateSet(errorKey).has(current)) { return true; } - current = target.baseModel; + current = current.baseModel; } return false; } From 85677555d7f3017ae7945aab9552ee436ebe9da0 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 29 Feb 2024 11:53:12 -0800 Subject: [PATCH 6/6] more tests --- packages/compiler/test/decorators/decorators.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/decorators/decorators.test.ts b/packages/compiler/test/decorators/decorators.test.ts index e65e34447d9..01758ad7342 100644 --- a/packages/compiler/test/decorators/decorators.test.ts +++ b/packages/compiler/test/decorators/decorators.test.ts @@ -388,11 +388,13 @@ describe("compiler: built-in decorators", () => { }); it("applies @error on derived models", async () => { - const { B } = await runner.compile(` + const { B, C } = await runner.compile(` @error model A { } @test model B extends A { } + @test model C extends B { } `); ok(isErrorModel(runner.program, B), "isError should be true"); + ok(isErrorModel(runner.program, C), "isError should be true"); }); it("emit diagnostic if error is not applied to a model", async () => {