From 00b781a5cc3715397fa8169503d32b09e688299e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 22 Sep 2026 21:01:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(vipeye-internal):=20str/bytes=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=80=E5=85=83=20'*'=20=E8=A7=A3=E5=BC=95=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E7=BB=93=E6=9E=9C=E4=B8=BA=20char?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Viper 里 str 与 bytes 都是 C 的 char*(i8*),`*s` 应取首字符且类型为 char(i8); 此前被当成非指针类型处理,报「类型 "str" 不支持运算符 "*"」(reportOperatorIssue)。 在 getTypeOfViperDeref 中把 str/bytes 与已有的 CPtr[X] 分支并列处理。 回归用例:viperUnaryPointer.test.ts 新增 *fmt(str)与 *buf(bytes)→ char, 并断言不报运算符错误。版本号提升至 1.1.419 并更新 CHANGELOG。 --- packages/vipeye-internal/package-lock.json | 4 +- packages/vipeye-internal/package.json | 2 +- .../src/analyzer/operations.ts | 7 +++ .../src/tests/viperUnaryPointer.test.ts | 61 +++++++++++++++++++ packages/vipeye/package-lock.json | 4 +- packages/vipeye/package.json | 2 +- packages/vscode-vipeye/CHANGELOG.md | 4 ++ packages/vscode-vipeye/package-lock.json | 4 +- packages/vscode-vipeye/package.json | 2 +- 9 files changed, 81 insertions(+), 9 deletions(-) diff --git a/packages/vipeye-internal/package-lock.json b/packages/vipeye-internal/package-lock.json index b8b6d75a..3d97ba65 100644 --- a/packages/vipeye-internal/package-lock.json +++ b/packages/vipeye-internal/package-lock.json @@ -1,12 +1,12 @@ { "name": "vipeye-internal", - "version": "1.1.418", + "version": "1.1.419", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vipeye-internal", - "version": "1.1.418", + "version": "1.1.419", "license": "MIT", "dependencies": { "@yarnpkg/fslib": "2.10.4", diff --git a/packages/vipeye-internal/package.json b/packages/vipeye-internal/package.json index 2a7e8b5e..a320a00a 100644 --- a/packages/vipeye-internal/package.json +++ b/packages/vipeye-internal/package.json @@ -2,7 +2,7 @@ "name": "vipeye-internal", "displayName": "vipeye", "description": "Type checker for the Viper language", - "version": "1.1.418", + "version": "1.1.419", "license": "MIT", "private": true, "files": [ diff --git a/packages/vipeye-internal/src/analyzer/operations.ts b/packages/vipeye-internal/src/analyzer/operations.ts index 47ab9517..8b2adccc 100644 --- a/packages/vipeye-internal/src/analyzer/operations.ts +++ b/packages/vipeye-internal/src/analyzer/operations.ts @@ -850,6 +850,7 @@ export function getTypeOfUnaryOperation( // Viper 扩展:一元 '*'(解引用)类型求值,与 C 语义一致。 // - CPtr[X](含 `X | t.CPtr` 化简形式)→ 返回目标类型 X(类对象转为实例) +// - str / bytes(C 的 char*,即 i8*)→ 返回 char(i8) // - Unknown/Any → 透传 // - 非指针类型 → 报错(C 语义:invalid type argument of unary '*') function getTypeOfViperDeref( @@ -867,6 +868,12 @@ function getTypeOfViperDeref( return subtype; } + // Viper:str / bytes 都是 C 的 char*(i8*),解引用取首字符,类型为 char(i8)。 + if (isClassInstance(subtype) && ClassType.isBuiltIn(subtype, ['str', 'bytes'])) { + resultTypes.push(evaluator.getBuiltInObject(node, 'char')); + return subtype; + } + if (isClassInstance(subtype) && isCPtrType(subtype)) { const typeArgs = subtype.priv.typeArgs; if (typeArgs && typeArgs.length > 0) { diff --git a/packages/vipeye-internal/src/tests/viperUnaryPointer.test.ts b/packages/vipeye-internal/src/tests/viperUnaryPointer.test.ts index ede48f09..816d8c82 100644 --- a/packages/vipeye-internal/src/tests/viperUnaryPointer.test.ts +++ b/packages/vipeye-internal/src/tests/viperUnaryPointer.test.ts @@ -458,3 +458,64 @@ def main() -> int: program.dispose(); serviceProvider.dispose(); }); + +// Viper:str / bytes 都是 C 的 char*(i8*),`*s` 取首字符,类型为 char(i8)。 +// 修复「类型 "str" 不支持运算符 "*"」(reportOperatorIssue)。 +test('Viper 解引用 str/bytes 返回 char', () => { + const code = `import t + +def test_str_deref(fmt: str) -> int: + c: char = *fmt + return 0 + +def test_bytes_deref(buf: bytes) -> int: + ch: char = *buf + return 0 +`; + const { program, configOptions, parseResults, uri, serviceProvider } = buildProgramForCode(code); + + const evaluator = program.evaluator as TypeEvaluator | undefined; + assert(evaluator, 'evaluator not available'); + const ev = evaluator; + + const derefs: { line: number; type: string }[] = []; + class UnaryCollector extends ParseTreeWalker { + override visitUnaryOperation(node: UnaryOperationNode) { + if (node.d.operator !== OperatorType.Multiply) { + return true; + } + const type = ev.getType(node as any); + derefs.push({ + line: convertOffsetToPosition(node.start, parseResults.parserOutput.lines).line + 1, + type: type ? program.printType(type) : '(undefined)', + }); + return true; + } + } + new UnaryCollector().walk(parseResults.parserOutput.parseTree); + + console.log('=== str/bytes 解引用类型 ==='); + derefs.forEach((d) => console.log(` L${d.line}: ${d.type}`)); + + // L4: *fmt(fmt: str,即 i8*)→ char + const strDeref = derefs.find((d) => d.line === 4); + assert(strDeref, '*fmt not found (L4)'); + assert.strictEqual(strDeref.type, 'char', `*fmt 应为 char,实际: ${strDeref.type}`); + + // L8: *buf(buf: bytes,即 i8*)→ char + const bytesDeref = derefs.find((d) => d.line === 8); + assert(bytesDeref, '*buf not found (L8)'); + assert.strictEqual(bytesDeref.type, 'char', `*buf 应为 char,实际: ${bytesDeref.type}`); + + // 不得报「类型 "str" / "bytes" 不支持运算符 "*"」 + const diagnostics = getDiagnostics(program, configOptions, uri); + console.log('=== 诊断 ==='); + diagnostics.forEach((d) => console.log(` ${d}`)); + assert( + !diagnostics.some((d) => d.includes('不支持运算符')), + `str/bytes 解引用不应报运算符错误: ${JSON.stringify(diagnostics)}` + ); + + program.dispose(); + serviceProvider.dispose(); +}); diff --git a/packages/vipeye/package-lock.json b/packages/vipeye/package-lock.json index 8570449d..c8df052b 100644 --- a/packages/vipeye/package-lock.json +++ b/packages/vipeye/package-lock.json @@ -1,12 +1,12 @@ { "name": "vipeye", - "version": "1.1.418", + "version": "1.1.419", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vipeye", - "version": "1.1.418", + "version": "1.1.419", "license": "MIT", "bin": { "vipeye": "index.js", diff --git a/packages/vipeye/package.json b/packages/vipeye/package.json index 6c8946d5..28924d8b 100644 --- a/packages/vipeye/package.json +++ b/packages/vipeye/package.json @@ -2,7 +2,7 @@ "name": "vipeye", "displayName": "Vipeye", "description": "Type checker for the Viper language", - "version": "1.1.418", + "version": "1.1.419", "license": "MIT", "author": { "name": "TermiNexus" diff --git a/packages/vscode-vipeye/CHANGELOG.md b/packages/vscode-vipeye/CHANGELOG.md index 487a6054..0471bc4c 100644 --- a/packages/vscode-vipeye/CHANGELOG.md +++ b/packages/vscode-vipeye/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 1.1.419 + +- Dereferencing `str` / `bytes` with the unary `*` operator no longer reports `reportOperatorIssue`: both are C `char*` (`i8*`) in Viper, so `*s` yields `char` (`i8`). Mirrors `t.CPtr[X]` dereferencing, which already returned the pointee type + ## 1.1.418 - **Built-in C basic type names**: `long` (`t.CLong`) and `longlong` (`t.CLongLong`) are now built-in typedefs, mirroring the compiler's `_CNAME_ALIAS` table (`char`, `short`, `long`, `unsigned` and friends are language built-ins that need no import). C's `long long` cannot be spelled with a space, so Viper writes `longlong`; the unsigned form stays available as `t.CUnsignedLongLong` diff --git a/packages/vscode-vipeye/package-lock.json b/packages/vscode-vipeye/package-lock.json index d926438a..bfb0217b 100644 --- a/packages/vscode-vipeye/package-lock.json +++ b/packages/vscode-vipeye/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-vipeye", - "version": "1.1.418", + "version": "1.1.419", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vscode-vipeye", - "version": "1.1.418", + "version": "1.1.419", "license": "MIT", "dependencies": { "mermaid": "^11.12.0", diff --git a/packages/vscode-vipeye/package.json b/packages/vscode-vipeye/package.json index 36eed43e..19bb4082 100644 --- a/packages/vscode-vipeye/package.json +++ b/packages/vscode-vipeye/package.json @@ -2,7 +2,7 @@ "name": "vscode-vipeye", "displayName": "Vipeye", "description": "VS Code language support for Viper (LSP client)", - "version": "1.1.418", + "version": "1.1.419", "private": true, "license": "MIT", "author": {