From d9b5015c71d6e273ed476aec71b58bbe9137fa2a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 16 Sep 2026 11:51:48 +0800 Subject: [PATCH] =?UTF-8?q?"feat(vipeye-internal):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=86=85=E7=BD=AE=20char=20=E7=B1=BB=E5=9E=8B=EF=BC=88?= =?UTF-8?q?=E5=A4=8D=E5=88=BB=20int=EF=BC=8C8=20=E4=BD=8D=E5=AD=97?= =?UTF-8?q?=E7=AC=A6/=E6=95=B4=E5=9E=8B=EF=BC=89feat(vipeye-internal):=20r?= =?UTF-8?q?owptr=20=E6=9B=B4=E5=90=8D=E4=B8=BA=20rawptr=EF=BC=88=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=99=A8=E5=86=85=E7=BD=AE=E8=A3=B8=E6=8C=87=E9=92=88?= =?UTF-8?q?=20typedef=EF=BC=89feat(vipeye-internal):=20None=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=87=BD=E6=95=B0=E4=BB=85=E5=85=81=E8=AE=B8=E8=A3=B8?= =?UTF-8?q?=20return/return=20Nonefix(vipeye-internal):=20builtins.vp=20?= =?UTF-8?q?=E5=8F=91=E7=8E=B0=E6=89=A9=E5=B1=95=E5=88=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=A5=96=E5=85=88=E7=9B=AE=E5=BD=95=E4=B8=8E=20includes=20?= =?UTF-8?q?=E5=AD=90=E7=9B=AE=E5=BD=95chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E8=87=B3=201.1.413=20=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20CHANGELOG"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vipeye-internal/package.json | 2 +- .../vipeye-internal/src/analyzer/program.ts | 8 +- .../src/analyzer/typeEvaluator.ts | 41 +++++++-- .../src/tests/viperBuiltinsVpTypedef.test.ts | 18 ++-- .../typeshed-fallback/stdlib/builtins.vpi | 84 +++++++++++++++++-- packages/vipeye/package.json | 2 +- packages/vscode-vipeye/CHANGELOG.md | 7 ++ packages/vscode-vipeye/package.json | 2 +- 8 files changed, 131 insertions(+), 33 deletions(-) diff --git a/packages/vipeye-internal/package.json b/packages/vipeye-internal/package.json index 703bf073..842ef45e 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.412", + "version": "1.1.413", "license": "MIT", "private": true, "files": [ diff --git a/packages/vipeye-internal/src/analyzer/program.ts b/packages/vipeye-internal/src/analyzer/program.ts index 59262bcf..9d4f0370 100644 --- a/packages/vipeye-internal/src/analyzer/program.ts +++ b/packages/vipeye-internal/src/analyzer/program.ts @@ -1891,7 +1891,7 @@ export class Program { getScopeIfAvailable(fileToBind.chainedSourceFile) ?? getScopeIfAvailable(fileToBind.builtinsImport); // Viper 扩展:将项目 includes 中 builtins.vp(真实源码,非 .vpi 存根) - // 的 t.CTypedef 类型别名(rowptr/size_t 等)合并进 builtin 作用域。 + // 的 t.CTypedef 类型别名(rawptr/size_t 等)合并进 builtin 作用域。 // 对齐 TransPyC TypeAnnotationResolver / TPV _lookup_builtins_typedef 的 // "builtins 最后匹配"语义:builtins 始终纳入编译链但不在用户文件的 // import 闭包内,其 typedef 声明需作为注解名解析的兜底。 @@ -1920,11 +1920,11 @@ export class Program { } // Viper 扩展:将项目 includes 中 builtins.vp(真实源码,非 .vpi 存根)的 - // t.CTypedef 类型别名(rowptr/size_t 等)合并进 builtin 作用域。 + // t.CTypedef 类型别名(rawptr/size_t 等)合并进 builtin 作用域。 // // 背景:TransPyC/TPV 的"builtins 最后匹配"——builtins 模块始终纳入编译链, // 但不在用户文件的 import 闭包内,其 `NAME: t.CTypedef = TYPE` 声明(如 - // builtins.vp 中的 rowptr = t.CPtr、size_t = __stdint.size_t)不随 + // builtins.vp 中的 rawptr = t.CPtr、size_t = __stdint.size_t)不随 // from_imports 注入,编译器按源文件扫描 builtins.vp 作为注解名解析兜底 // (见 TransPyC lib/core/TypeAnnotationResolver.py)。 // @@ -2017,7 +2017,7 @@ export class Program { } // 合并:builtins.vp 的声明优先覆盖 builtin 作用域(完全对齐真实编译器, - // 如 ord/chr 的 t.CChar 签名、min/max 的 double 签名、rowptr/size_t 等 typedef)。 + // 如 ord/chr 的 t.CChar 签名、min/max 的 double 签名、rawptr/size_t 等 typedef)。 // 覆盖范围:t.CTypedef 类型别名声明 + 函数声明;跳过模块别名(__stdint/t) // 与隐式 dunder 符号,避免引入不必要的隐式全局。 for (const [name, symbol] of builtinsVpScope.symbolTable) { diff --git a/packages/vipeye-internal/src/analyzer/typeEvaluator.ts b/packages/vipeye-internal/src/analyzer/typeEvaluator.ts index 19d899cf..3097d40c 100644 --- a/packages/vipeye-internal/src/analyzer/typeEvaluator.ts +++ b/packages/vipeye-internal/src/analyzer/typeEvaluator.ts @@ -18490,8 +18490,8 @@ export function createTypeEvaluator( EvalFlags.NoClassVar; // Viper 扩展:保留上方"裸类引用 RHS 不专用化"的 NoSpecialize 标志。 - // 否则 `rowptr: t.CTypedef = t.CPtr` 的 RHS 会被 reportMissingTypeArgs - // 预填成 CPtr[Unknown],导致 `rowptr[int]` 无法再特化 + // 否则 `rawptr: t.CTypedef = t.CPtr` 的 RHS 会被 reportMissingTypeArgs + // 预填成 CPtr[Unknown],导致 `rawptr[int]` 无法再特化 // (下标处报"类型 CPtr[Unknown] 已专用化")。 if ( node.d.rightExpr.nodeType === ParseNodeType.Name || @@ -26733,12 +26733,12 @@ export function createTypeEvaluator( } } - // Viper 扩展:字符串字面量 → int(CChar)转换语义。 + // Viper 扩展:字符串字面量 → int(CChar)/ char 转换语义。 // C 语言中 char c = '_' 合法(字符字面量是整数)。Viper 中 CChar 是 int 别名, - // 但 '_' 是字符串字面量。允许字符串字面量赋值给 int,模拟 C 的字符赋值。 + // 但 '_' 是字符串字面量。允许字符串字面量赋值给 int / 内置 char,模拟 C 的字符赋值。 // Python 中 str 永远不能赋值给 int,所以此扩展只在 Viper 场景生效。 if ( - isClassInstance(destType) && ClassType.isBuiltIn(destType, 'int') && + isClassInstance(destType) && ClassType.isBuiltIn(destType, ['int', 'char']) && isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'str') && srcType.priv.literalValue !== undefined && typeof srcType.priv.literalValue === 'string' @@ -26770,6 +26770,28 @@ export function createTypeEvaluator( return true; } + // Viper 扩展:内置 char(8 位字符/整型,C 的 char)隐式转换。 + // char 与 int 同为整数类型,按 C 整数隐式转换规则互转(所有方向); + // char → float/double 无损(8 位 → 32/64 位浮点);浮点 → char 不允许(有损)。 + if ( + isClassInstance(destType) && ClassType.isBuiltIn(destType, 'char') && + isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'int') + ) { + return true; + } + if ( + isClassInstance(destType) && ClassType.isBuiltIn(destType, 'int') && + isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'char') + ) { + return true; + } + if ( + isClassInstance(destType) && ClassType.isBuiltIn(destType, ['float', 'double']) && + isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'char') + ) { + return true; + } + // Viper 扩展:CEnum 子类 → int 隐式转换语义。 // C 语言中 enum 值可以隐式转换为 int(如 int x = FR_OK)。 // Viper 的 CEnum 子类(如 FRESULT)的成员(如 FRESULT.FR_OK) @@ -26785,20 +26807,21 @@ export function createTypeEvaluator( // Viper 中所有 C 类型(CInt, CFloat, CChar 等)都是 CType 的子类, // 在底层等价于 Python 内置类型(int, float, str 等)。 // 允许 `k: t.CInt = 1`(int → CInt)、`k: t.CFloat = 1.0`(float → CFloat)等赋值。 - // double 为 Viper 内置 64 位浮点,可赋给 t.CDouble。 + // double 为 Viper 内置 64 位浮点,可赋给 t.CDouble;char 为内置 8 位字符,可赋给 t.CChar。 if ( isClassInstance(destType) && isCTypeSubclassType(destType) && - isClassInstance(srcType) && ClassType.isBuiltIn(srcType, ['int', 'float', 'double', 'str', 'bool', 'bytes']) + isClassInstance(srcType) && ClassType.isBuiltIn(srcType, ['int', 'float', 'double', 'char', 'str', 'bool', 'bytes']) ) { return true; } // Viper 扩展:CType 子类 -> Python 内置类型隐式转换(反向)。 // CInt/CFloat/CChar 等 CType 子类在底层等价于 Python 内置类型, - // 可隐式转换回 int/float/str/bool/bytes(含 t.CDouble → 内置 double)。 + // 可隐式转换回 int/float/double/char/str/bool/bytes(含 t.CDouble → 内置 double、 + // t.CChar → 内置 char)。 // 覆盖场景:CInt 值传给 int 形参(如 def __init__(self, w: int) 接收 CInt 实参)。 if ( - isClassInstance(destType) && ClassType.isBuiltIn(destType, ['int', 'float', 'double', 'str', 'bool', 'bytes']) && + isClassInstance(destType) && ClassType.isBuiltIn(destType, ['int', 'float', 'double', 'char', 'str', 'bool', 'bytes']) && isClassInstance(srcType) && isCTypeSubclassType(srcType) ) { return true; diff --git a/packages/vipeye-internal/src/tests/viperBuiltinsVpTypedef.test.ts b/packages/vipeye-internal/src/tests/viperBuiltinsVpTypedef.test.ts index c4790d56..d7bc6e1e 100644 --- a/packages/vipeye-internal/src/tests/viperBuiltinsVpTypedef.test.ts +++ b/packages/vipeye-internal/src/tests/viperBuiltinsVpTypedef.test.ts @@ -1,14 +1,12 @@ /* * viperBuiltinsVpTypedef.test.ts * - * 验证 Viper 方言下注解名解析对 includes/builtins.vp(真实源码,非 .vpi 存根) - * 中 t.CTypedef 类型别名的兜底搜索("builtins 最后匹配",对齐 TransPyC - * TypeAnnotationResolver / TPV _lookup_builtins_typedef): - * - `rowptr[int]` 注解 → rowptr 为 builtins.vp 中的 typedef,可解析为 CPtr[int] - * - `size_t` 注解 → 解析为 t.CSizeT - * - `int8` 注解 → 解析为 t.CInt8T + * 验证 Viper 方言下注解名解析对内置 typedef 的兜底搜索: + * - `rawptr[int]` 注解 → rawptr 为 builtins.vpi 中的编译器内置 typedef,可解析为 CPtr[int] + * - `size_t` 注解 → 解析为 t.CSizeT(来自 includes/builtins.vp 的 t.CTypedef 别名) + * - `int8` 注解 → 解析为 t.CInt8T(来自 includes/builtins.vp 的 t.CTypedef 别名) * - 均无需显式 import builtins(builtins 不在用户文件 import 闭包内) - * - 不报"未定义 rowptr/size_t/int8" + * - 不报"未定义 rawptr/size_t/int8" * * 运行:npx jest src/tests/viperBuiltinsVpTypedef.test.ts --runInBand */ @@ -106,7 +104,7 @@ function collectParamAnnotationTypes( test('builtins.vp(includes 版本)typedef 在注解中可直接解析', () => { const source = `import t -def f(x: rowptr[int]) -> int: +def f(x: rawptr[int]) -> int: return 0 def g() -> size_t: @@ -128,7 +126,7 @@ def h(a: int8) -> int: `builtins.vp typedef 不应报未定义,实际: ${JSON.stringify(undefinedDiags)}` ); - // 2. 参数注解类型解析:rowptr[int] → CPtr[int] + // 2. 参数注解类型解析:rawptr[int] → CPtr[int] const types = collectParamAnnotationTypes(program, parseResults!); const fTypes = types.get('f'); assert(fTypes && fTypes.some((t) => t.includes('CPtr') && t.includes('int')), `f(x) 应为 CPtr[int],实际: ${JSON.stringify(fTypes)}`); @@ -168,7 +166,7 @@ def h(a: int8) -> int: test('builtins.vp typedef 与 builtins.vpi 内建并存(int/str 等不被破坏)', () => { const source = `import t -def f(x: rowptr[int]) -> str: +def f(x: rawptr[int]) -> str: s: str = "ok" return s `; diff --git a/packages/vipeye-internal/typeshed-fallback/stdlib/builtins.vpi b/packages/vipeye-internal/typeshed-fallback/stdlib/builtins.vpi index 1586efe1..d70a7eb3 100644 --- a/packages/vipeye-internal/typeshed-fallback/stdlib/builtins.vpi +++ b/packages/vipeye-internal/typeshed-fallback/stdlib/builtins.vpi @@ -506,6 +506,76 @@ class double: @classmethod def from_number(cls, number: float | SupportsIndex | SupportsFloat, /) -> Self: ... +@disjoint_base +class char: + """char 类型(8 位字符/整型,C 的 char,定义复刻 int)。""" + + @overload + def __new__(cls, x: ConvertibleToInt = 0, /) -> Self: ... + @overload + def __new__(cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self: ... + + @property + def real(self) -> char: ... + @property + def imag(self) -> char: ... + def conjugate(self) -> char: ... + def bit_length(self) -> int: ... + def bit_count(self) -> int: ... + + def __add__(self, value: int, /) -> char: ... + def __sub__(self, value: int, /) -> char: ... + def __mul__(self, value: int, /) -> char: ... + def __floordiv__(self, value: int, /) -> char: ... + def __truediv__(self, value: int, /) -> float: ... + def __mod__(self, value: int, /) -> char: ... + def __divmod__(self, value: int, /) -> tuple[char, char]: ... + def __radd__(self, value: int, /) -> char: ... + def __rsub__(self, value: int, /) -> char: ... + def __rmul__(self, value: int, /) -> char: ... + def __rfloordiv__(self, value: int, /) -> char: ... + def __rtruediv__(self, value: int, /) -> float: ... + def __rmod__(self, value: int, /) -> char: ... + def __rdivmod__(self, value: int, /) -> tuple[char, char]: ... + + @overload + def __pow__(self, value: _PositiveInteger, mod: None = None, /) -> char: ... + @overload + def __pow__(self, value: _NegativeInteger, mod: None = None, /) -> float: ... + # positive __value -> char; negative __value -> float + # return type must be Any as `char | float` causes too many false-positive errors + @overload + def __pow__(self, value: int, mod: None = None, /) -> Any: ... + + def __rpow__(self, value: int, mod: int | None = None, /) -> Any: ... + def __and__(self, value: int, /) -> char: ... + def __or__(self, value: int, /) -> char: ... + def __xor__(self, value: int, /) -> char: ... + def __lshift__(self, value: int, /) -> char: ... + def __rshift__(self, value: int, /) -> char: ... + def __rand__(self, value: int, /) -> char: ... + def __ror__(self, value: int, /) -> char: ... + def __rxor__(self, value: int, /) -> char: ... + def __rlshift__(self, value: int, /) -> char: ... + def __rrshift__(self, value: int, /) -> char: ... + def __neg__(self) -> char: ... + def __pos__(self) -> char: ... + def __invert__(self) -> char: ... + def __getnewargs__(self) -> tuple[char]: ... + def __eq__(self, value: object, /) -> bool: ... + def __ne__(self, value: object, /) -> bool: ... + def __lt__(self, value: int, /) -> bool: ... + def __le__(self, value: int, /) -> bool: ... + def __gt__(self, value: int, /) -> bool: ... + def __ge__(self, value: int, /) -> bool: ... + def __float__(self) -> float: ... + def __int__(self) -> int: ... + def __abs__(self) -> char: ... + def __hash__(self) -> int: ... + def __bool__(self) -> bool: ... + def __index__(self) -> int: ... + def __format__(self, format_spec: str, /) -> str: ... + @disjoint_base class complex: # Python doesn't currently accept SupportsComplex for the second argument @@ -2664,11 +2734,11 @@ def LOut(expr: Any, constraint: Any = None) -> Any: """LLVM IR 输出操作数标记(等价 c.LOut)。""" ... -# --- Viper 扩展:编译器内置裸指针类型 rowptr --- -# rowptr 是编译器内置类型(TPC/TPV 双端,语法保留字,不可重定义): -# rowptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]), -# 单独 rowptr 等价 t.CPtr(void*)。 -# 声明在 builtins stub 中使 LSP 对任意 Viper 工程均可解析 rowptr,不依赖 -# 项目 includes/builtins.vp 是否声明;编译器侧解析 rowptr 时优先走内置 +# --- Viper 扩展:编译器内置裸指针类型 rawptr --- +# rawptr 是编译器内置类型(TPC/TPV 双端,语法保留字,不可重定义): +# rawptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]), +# 单独 rawptr 等价 t.CPtr(void*)。 +# 声明在 builtins stub 中使 LSP 对任意 Viper 工程均可解析 rawptr,不依赖 +# 项目 includes/builtins.vp 是否声明;编译器侧解析 rawptr 时优先走内置 # 路径并忽略本声明(见 TransPyC TypeAnnotationResolver / SymbolExtractor)。 -rowptr: t.CTypedef = t.CPtr \ No newline at end of file +rawptr: t.CTypedef = t.CPtr \ No newline at end of file diff --git a/packages/vipeye/package.json b/packages/vipeye/package.json index 9ef2991a..5a6212d4 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.412", + "version": "1.1.413", "license": "MIT", "author": { "name": "TermiNexus" diff --git a/packages/vscode-vipeye/CHANGELOG.md b/packages/vscode-vipeye/CHANGELOG.md index 33377176..6bef4b35 100644 --- a/packages/vscode-vipeye/CHANGELOG.md +++ b/packages/vscode-vipeye/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## 1.1.413 + +- **内置 char 类型**:复刻 int 定义(8 位字符/整型),与 `t.CChar`、`int` 双向隐式转换,`char → float/double` 无损 +- **内置 rawptr**:编译器内置裸指针 typedef(`rawptr: t.CTypedef = t.CPtr`),任意工程可直接用 `rawptr[T]`,不依赖项目 includes 配置 +- 类型检查:`-> None` 函数只允许裸 `return` / `return None`,`return` 值为 None 的表达式(如调用返回 None 的函数)报错 +- 导入解析:builtins.vp 发现扩展到被分析文件祖先目录与 `includes/` 子目录,修复未显式配置 includes 时 `uint64` 等 typedef 报"未定义" + ## 1.1.412 - **整合 Viper 核心扩展**:侧边栏活动栏(Project/Toolchain/Settings 视图)、.vpj 项目管理、工具链选择与状态栏并入本扩展,一个包即可使用全部 Viper 功能 diff --git a/packages/vscode-vipeye/package.json b/packages/vscode-vipeye/package.json index 7bbeeb4a..33c94fd5 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.412", + "version": "1.1.413", "private": true, "license": "MIT", "author": {