"feat(vipeye-internal): 新增内置 char 类型(复刻 int,8 位字符/整型)feat(vipeye-internal): rowptr 更名为 rawptr(编译器内置裸指针 typedef)feat(vipeye-internal): None 返回函数仅允许裸 return/return Nonefix(vipeye-internal): builtins.vp 发现扩展到文件祖先目录与 includes 子目录chore: 版本号提升至 1.1.413 并更新 CHANGELOG"
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

This commit is contained in:
TermiNexus committed 2026-09-16 11:51:48 +08:00
1 parent aef18c2891
commit d9b5015c71
8 files changed
+131 -33

No files matched your search

+1 -1
View File
@@ -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": [
@@ -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) {
@@ -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;
@@ -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
`;
@@ -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
rawptr: t.CTypedef = t.CPtr
+1 -1
View File
@@ -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"
+7
View File
@@ -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 功能
+1 -1
View File
@@ -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": {