refactor(vipeye-internal): str/bytes 下标统一返回 char(与 *s 解引用一致)
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled

`s[i]` 原返回 t.CChar,而 `*s` 返回 char,同一 i8 元素出现两种显示。现把 str/bytes
的下标通路(普通下标 + TypeSet 下标)统一改为内置 char 对象,二者本就可隐式互转。
迭代(for ch in s)与 Iterable 实参推断仍保持 t.CChar,待确认是否一并统一。

回归用例:viperUnaryPointer.test.ts 中 fmt[0] 断言改为 char。
版本号提升至 1.1.421 并更新 CHANGELOG。
This commit is contained in:
TermiNexus committed 2026-09-22 21:26:16 +08:00
1 parent 1aa1b1f2f0
commit d2f66811fb
9 files changed
+24 -35

No files matched your search

+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "vipeye-internal",
"version": "1.1.420",
"version": "1.1.421",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vipeye-internal",
"version": "1.1.420",
"version": "1.1.421",
"license": "MIT",
"dependencies": {
"@yarnpkg/fslib": "2.10.4",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "vipeye-internal",
"displayName": "vipeye",
"description": "Type checker for the Viper language",
"version": "1.1.420",
"version": "1.1.421",
"license": "MIT",
"private": true,
"files": [
@@ -8412,17 +8412,9 @@ export function createTypeEvaluator(
if (isClassInstance(concreteSubtype)) {
// Viper TypeSet:str/bytes 在类型组合中表示 C 字符串指针(i8*),
// 下标访问 a[i] 应返回 t.CChar(int 别名),而非 str/bytes。
if (
isViperTypeSetIndex &&
ClassType.isBuiltIn(concreteSubtype, ['str', 'bytes'])
) {
// 构造带 CChar 别名信息的 int 类型(保留 t.CChar 显示信息)
const ccharType = getViperCCharType(node);
if (ccharType) {
return ccharType;
}
return concreteSubtype;
// 下标访问 a[i] 应返回 char(i8 字符),而非 str/bytes。
if (isViperTypeSetIndex && ClassType.isBuiltIn(concreteSubtype, ['str', 'bytes'])) {
return getBuiltInObject(node, 'char');
}
// Viper TypeSet:非修饰基本类型(int/float/bool 等)在类型组合中
// 表示指针指向的目标类型(如 CConst | int | CPtr = const int*),
@@ -8435,20 +8427,16 @@ export function createTypeEvaluator(
) {
return concreteSubtype;
}
// Viper 扩展:str/bytes 表示 C 字符串指针(i8* / i8*)。
// Viper 扩展:str/bytes 表示 C 字符串指针(i8*)。
// 无论读写,下标访问 a[i] 都是指针解引用操作(C 语义):
// - 读取 a[i] 返回 t.CChar(i8 字节),而非 Python str.__getitem__ 的 str
// - 读取 a[i] 返回 char(i8 字节),与解引用 `*a` 的结果类型一致,
// 而非 Python str.__getitem__ 的 str
// - 赋值 a[i] = v 是合法的指针写字节操作,不报 __setitem__ 不存在
if (
IsViperDialect(viperIndexFileInfo.executionEnvironment.dialect) &&
ClassType.isBuiltIn(concreteSubtype, ['str', 'bytes'])
) {
// 构造带 CChar 别名信息的 int 类型作为下标访问的目标类型
const ccharType = getViperCCharType(node);
if (ccharType) {
return ccharType;
}
return concreteSubtype;
return getBuiltInObject(node, 'char');
}
const typeResult = getTypeOfIndexedObjectOrClass(node, concreteSubtype, selfType, usage);
if (typeResult.isIncomplete) {
@@ -587,13 +587,10 @@ def test_str_arith(fmt: str) -> int:
assert.strictEqual(op.type, 'str', `指针算术结果应为 str (L${line}),实际: ${op.type}`);
}
// L7:fmt[0] → t.CChar(C 的 char 字节;与 `*fmt` 的 char 可隐式互转)
// L7:fmt[0] → char(与 `*fmt` 解引用统一为同一元素类型)
const subscript = indexTypes.find((i) => i.line === 7);
assert(subscript, `下标访问未找到 (L7)`);
assert(
subscript.type.includes('CChar'),
`fmt[0] 应为 t.CChar,实际: ${subscript.type}`
);
assert.strictEqual(subscript.type, 'char', `fmt[0] 应为 char,实际: ${subscript.type}`);
const diagnostics = getDiagnostics(program, configOptions, uri);
console.log('=== 诊断 ===');
diagnostics.forEach((d) => console.log(` ${d}`));
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "vipeye",
"version": "1.1.420",
"version": "1.1.421",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vipeye",
"version": "1.1.420",
"version": "1.1.421",
"license": "MIT",
"bin": {
"vipeye": "index.js",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "vipeye",
"displayName": "Vipeye",
"description": "Type checker for the Viper language",
"version": "1.1.420",
"version": "1.1.421",
"license": "MIT",
"author": {
"name": "TermiNexus"
+5 -1
View File
@@ -1,8 +1,12 @@
# Change Log
## 1.1.421
- `s[i]` on `str` / `bytes` now yields `char` (`i8`) instead of `t.CChar`, matching the dereference result of `*s` (the two remain implicitly convertible). Covers both the plain subscript path and the type-set subscript path (e.g. `CConst | str | CPtr` style annotations); iteration (`for ch in s`) and `Iterable` argument inference still produce `t.CChar`
## 1.1.420
- Pointer semantics for `str` / `bytes` (both are C `char*`, `i8*`) now cover pointer arithmetic and writes, matching the dereference support added earlier: `p + n`, `p - n` and `n + p` return the pointer type instead of reporting `reportOperatorIssue`, and `*p = v` is accepted as an assignment target. `p[i]` already yielded `t.CChar` and is unchanged
- Pointer semantics for `str` / `bytes` (both are C `char*`, `i8*`) now cover pointer arithmetic and writes, matching the dereference support added earlier: `p + n`, `p - n` and `n + p` return the pointer type instead of reporting `reportOperatorIssue`, and `*p = v` is accepted as an assignment target. Subscript access `p[i]` was already supported
- Built-in C basic type names extended with `short` (`t.CShort`), `ushort` (`t.CUnsignedShort`), `ulong` (`t.CUnsignedLong`) and `ulonglong` (`t.CUnsignedLongLong`), alongside the existing `long` / `longlong`
## 1.1.419
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "vscode-vipeye",
"version": "1.1.420",
"version": "1.1.421",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vscode-vipeye",
"version": "1.1.420",
"version": "1.1.421",
"license": "MIT",
"dependencies": {
"mermaid": "^11.12.0",
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "vscode-vipeye",
"name": "vipeye",
"displayName": "Vipeye",
"description": "VS Code language support for Viper (LSP client)",
"version": "1.1.420",
"version": "1.1.421",
"private": true,
"license": "MIT",
"author": {