From cbb25d51bd7893edd67224ea38220fcaa280137b Mon Sep 17 00:00:00 2001 From: takejohn Date: Fri, 5 Dec 2025 19:04:16 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E5=9E=8B=E5=BC=95=E6=95=B0=E5=90=8D?= =?UTF-8?q?=E3=81=AE=E9=87=8D=E8=A4=87=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=8C=E9=81=A9=E5=88=87=E3=81=AB?= =?UTF-8?q?=E7=99=BA=E7=94=9F=E3=81=97=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/plugins/validate-type.ts | 19 ++++++++++++------- test/types.ts | 14 ++++++++++---- ...fix-duplicate-type-parameter-name-error.md | 2 ++ 3 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 unreleased/fix-duplicate-type-parameter-name-error.md diff --git a/src/parser/plugins/validate-type.ts b/src/parser/plugins/validate-type.ts index 1d043919..c9e54758 100644 --- a/src/parser/plugins/validate-type.ts +++ b/src/parser/plugins/validate-type.ts @@ -1,17 +1,21 @@ import { getTypeBySource } from '../../type.js'; import { visitNode } from '../visit.js'; +import { AiScriptTypeError } from '../../error.js'; import type * as Ast from '../../node.js'; +function validateTypeParams(node: Ast.Fn): void { + const typeParamNames = new Set(); + for (const typeParam of node.typeParams) { + if (typeParamNames.has(typeParam.name)) { + throw new AiScriptTypeError(`type parameter name ${typeParam.name} is duplicate`, node.loc.start); + } + typeParamNames.add(typeParam.name); + } +} + function collectTypeParams(node: Ast.Node, ancestors: Ast.Node[]): Ast.TypeParam[] { const items = []; if (node.type === 'fn') { - const typeParamNames = new Set(); - for (const typeParam of node.typeParams) { - if (typeParamNames.has(typeParam.name)) { - throw new Error(`type parameter name ${typeParam.name} is duplicate`); - } - typeParamNames.add(typeParam.name); - } items.push(...node.typeParams); } for (let i = ancestors.length - 1; i >= 0; i--) { @@ -32,6 +36,7 @@ function validateNode(node: Ast.Node, ancestors: Ast.Node[]): Ast.Node { break; } case 'fn': { + validateTypeParams(node); for (const param of node.params) { if (param.argType != null) { getTypeBySource(param.argType, collectTypeParams(node, ancestors)); diff --git a/test/types.ts b/test/types.ts index d876e00a..24d11058 100644 --- a/test/types.ts +++ b/test/types.ts @@ -1,8 +1,8 @@ import * as assert from 'assert'; -import { describe, test } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { utils } from '../src'; import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value'; -import { AiScriptRuntimeError } from '../src/error'; +import { AiScriptRuntimeError, AiScriptTypeError } from '../src/error'; import { exe, getMeta, eq } from './testutils'; describe('function types', () => { @@ -98,9 +98,15 @@ describe('generics', () => { }); test.concurrent('duplicate', async () => { - await assert.rejects(() => exe(` + await expect(() => exe(` @f(v: T) {} - `)); + `)).rejects.toThrow(AiScriptTypeError); + }); + + test.concurrent('duplicate (no param and ret types)', async () => { + await expect(() => exe(` + @f() {} + `)).rejects.toThrow(AiScriptTypeError); }); test.concurrent('empty', async () => { diff --git a/unreleased/fix-duplicate-type-parameter-name-error.md b/unreleased/fix-duplicate-type-parameter-name-error.md new file mode 100644 index 00000000..362fcea5 --- /dev/null +++ b/unreleased/fix-duplicate-type-parameter-name-error.md @@ -0,0 +1,2 @@ +- Fix: 関数の型引数の名前が重複した場合に適切なエラーが発生しない問題を修正 +- Fix: 関数の引数や返り値に型注釈が無く、型引数の名前が重複した場合にエラーが発生しない問題を修正 From 79ef1893d5708c6cf1eab19e6cdb1ae0dba99f90 Mon Sep 17 00:00:00 2001 From: takejohn Date: Fri, 5 Dec 2025 21:36:37 +0900 Subject: [PATCH 2/2] =?UTF-8?q?AiScriptSyntaxError=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/plugins/validate-type.ts | 4 ++-- test/types.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/parser/plugins/validate-type.ts b/src/parser/plugins/validate-type.ts index c9e54758..3c42ba5d 100644 --- a/src/parser/plugins/validate-type.ts +++ b/src/parser/plugins/validate-type.ts @@ -1,13 +1,13 @@ import { getTypeBySource } from '../../type.js'; import { visitNode } from '../visit.js'; -import { AiScriptTypeError } from '../../error.js'; +import { AiScriptSyntaxError } from '../../error.js'; import type * as Ast from '../../node.js'; function validateTypeParams(node: Ast.Fn): void { const typeParamNames = new Set(); for (const typeParam of node.typeParams) { if (typeParamNames.has(typeParam.name)) { - throw new AiScriptTypeError(`type parameter name ${typeParam.name} is duplicate`, node.loc.start); + throw new AiScriptSyntaxError(`type parameter name ${typeParam.name} is duplicate`, node.loc.start); } typeParamNames.add(typeParam.name); } diff --git a/test/types.ts b/test/types.ts index 24d11058..63ad5db2 100644 --- a/test/types.ts +++ b/test/types.ts @@ -2,7 +2,7 @@ import * as assert from 'assert'; import { describe, expect, test } from 'vitest'; import { utils } from '../src'; import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value'; -import { AiScriptRuntimeError, AiScriptTypeError } from '../src/error'; +import { AiScriptRuntimeError, AiScriptSyntaxError } from '../src/error'; import { exe, getMeta, eq } from './testutils'; describe('function types', () => { @@ -100,13 +100,13 @@ describe('generics', () => { test.concurrent('duplicate', async () => { await expect(() => exe(` @f(v: T) {} - `)).rejects.toThrow(AiScriptTypeError); + `)).rejects.toThrow(AiScriptSyntaxError); }); test.concurrent('duplicate (no param and ret types)', async () => { await expect(() => exe(` @f() {} - `)).rejects.toThrow(AiScriptTypeError); + `)).rejects.toThrow(AiScriptSyntaxError); }); test.concurrent('empty', async () => {