refactor(vipeye-internal): str/bytes 迭代元素类型统一为 char
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
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
接上次下标统一:`for ch in s` 的迭代元素,以及 str/bytes 作为 Iterable/Iterator 实参 时的泛型推断(enumerate/zip/map/filter/reversed/sorted/list() 等)也由 t.CChar 别名 int 改为内置 char。至此 `s[i]`、`*s`、迭代三种取字符方式元素类型一致。 删除已无引用的 getViperCCharType 辅助函数。 回归用例:viperEnumerate.test.ts 断言改为 enumerate[char] / ch 为 char。 版本号提升至 1.1.422 并更新 CHANGELOG。
This commit is contained in:
1 parent
d2f66811fb
commit
988ba922f4
9 files changed
+30
-81
No files matched your search
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "vipeye-internal",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vipeye-internal",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@yarnpkg/fslib": "2.10.4",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "vipeye-internal",
|
||||
"displayName": "vipeye",
|
||||
"description": "Type checker for the Viper language",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"files": [
|
||||
|
||||
@@ -3291,15 +3291,11 @@ export function createTypeEvaluator(
|
||||
}
|
||||
return UnknownType.create(isIncomplete);
|
||||
}
|
||||
// Viper 扩展:str/bytes 类型迭代返回 t.CChar(字符)。
|
||||
// Viper 语义:str/bytes = i8* 指针(const char*),迭代返回单个字符 CChar。
|
||||
// 使用 getViperCCharType 而非裸 int,保持与 s[i] 下标访问一致(t.CChar 显示)。
|
||||
// Viper 扩展:str/bytes 类型迭代返回 char(i8 字符)。
|
||||
// Viper 语义:str/bytes = i8* 指针(const char*),迭代返回单个字符。
|
||||
// 与下标访问 s[i]、解引用 *s 保持同一元素类型 char。
|
||||
if (ClassType.isBuiltIn(subtype, ['str', 'bytes'])) {
|
||||
const ccharType = getViperCCharType(errorNode);
|
||||
if (ccharType) {
|
||||
return ccharType;
|
||||
}
|
||||
return getBuiltInObject(errorNode, 'int');
|
||||
return getBuiltInObject(errorNode, 'char');
|
||||
}
|
||||
// 检查联合类型中是否包含 CPtr
|
||||
const typeContainsCPtr = findSubtype(type, (s) =>
|
||||
@@ -8728,57 +8724,6 @@ export function createTypeEvaluator(
|
||||
return getViperREnumVariantFieldInfo(renumType, memberName)?.type;
|
||||
}
|
||||
|
||||
// Viper 扩展:构造带 t.CChar 类型别名信息的 int 类型(表示 C 的 char 类型)。
|
||||
// Viper 中 str/bytes 是 i8* 指针,下标访问/迭代/字符运算返回 t.CChar(int 别名)。
|
||||
// 优先从 t 模块查找 CChar 类型别名以保留显示信息;找不到时回退为
|
||||
// 构造带 typeAliasInfo 的 int 类型。查找失败返回 undefined。
|
||||
function getViperCCharType(node: ExpressionNode): Type | undefined {
|
||||
const tSymbolWithScope = lookUpSymbolRecursive(node, 't', /* honorCodeFlow */ true);
|
||||
if (tSymbolWithScope) {
|
||||
const tEffectiveType = getEffectiveTypeOfSymbolForUsage(
|
||||
tSymbolWithScope.symbol,
|
||||
/* usageNode */ undefined,
|
||||
/* useLastDecl */ true
|
||||
).type;
|
||||
if (tEffectiveType && isModule(tEffectiveType)) {
|
||||
const ccharSymbol = ModuleType.getField(tEffectiveType, 'CChar');
|
||||
if (ccharSymbol) {
|
||||
// 优先使用声明类型(保留 typeAliasInfo)
|
||||
const ccharDeclType = getDeclaredTypeOfSymbol(ccharSymbol)?.type;
|
||||
if (ccharDeclType) {
|
||||
return convertToInstance(ccharDeclType);
|
||||
}
|
||||
// 回退到有效类型
|
||||
const ccharType = getEffectiveTypeOfSymbolForUsage(
|
||||
ccharSymbol,
|
||||
/* usageNode */ undefined,
|
||||
/* useLastDecl */ true
|
||||
).type;
|
||||
if (ccharType) {
|
||||
return convertToInstance(ccharType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 回退:构造带 CChar 别名信息的 int 类型
|
||||
const fileInfo = AnalyzerNodeInfo.getFileInfo(node);
|
||||
const intType = getBuiltInObject(node, 'int');
|
||||
const ccharAliasInfo: TypeAliasInfo = {
|
||||
shared: {
|
||||
name: 'CChar',
|
||||
fullName: 't.CChar',
|
||||
moduleName: 't',
|
||||
fileUri: fileInfo.fileUri,
|
||||
typeVarScopeId: '',
|
||||
isTypeAliasType: false,
|
||||
typeParams: undefined,
|
||||
computedVariance: undefined,
|
||||
},
|
||||
typeArgs: undefined,
|
||||
};
|
||||
return TypeBase.cloneForTypeAlias(intType, ccharAliasInfo);
|
||||
}
|
||||
|
||||
function getTypeOfIndexedObjectOrClass(
|
||||
node: IndexNode,
|
||||
baseType: ClassType,
|
||||
@@ -14195,8 +14140,8 @@ export function createTypeEvaluator(
|
||||
if (expectedType && requiresSpecialization(expectedType)) {
|
||||
// Viper 扩展:str/bytes 实参传给可迭代协议参数(Iterable[_T]/Iterator[_T] 等)
|
||||
// 时,泛型参数 _T 应从 str.__iter__ 的声明返回类型(Iterator[str])推断。
|
||||
// 但 Viper 中 str 是 i8* 指针,迭代元素应为 t.CChar 而非 str。
|
||||
// 因此将 argType 替换为 Iterator[CChar] 实例,使协议匹配把 _T 绑定为 CChar,
|
||||
// 但 Viper 中 str 是 i8* 指针,迭代元素应为 char 而非 str。
|
||||
// 因此将 argType 替换为 Iterator[char] 实例,使协议匹配把 _T 绑定为 char,
|
||||
// 修复 `for i, ch in enumerate(src)` 中 ch 被推断为 str 的问题
|
||||
// (同样覆盖 zip/map/filter/reversed/sorted/list() 等 Iterable 参数场景)。
|
||||
let argTypeForConstraint = argType;
|
||||
@@ -14205,11 +14150,11 @@ export function createTypeEvaluator(
|
||||
isClassInstance(argType) &&
|
||||
ClassType.isBuiltIn(argType, ['str', 'bytes'])
|
||||
) {
|
||||
const ccharType = getViperCCharType(argParam.errorNode);
|
||||
const charType = getBuiltInObject(argParam.errorNode, 'char');
|
||||
const iteratorClass = getTypingType(argParam.errorNode, 'Iterator');
|
||||
if (ccharType && iteratorClass && isInstantiableClass(iteratorClass)) {
|
||||
if (iteratorClass && isInstantiableClass(iteratorClass)) {
|
||||
argTypeForConstraint = ClassType.cloneAsInstance(
|
||||
ClassType.specialize(iteratorClass, [ccharType])
|
||||
ClassType.specialize(iteratorClass, [charType])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* viperEnumerate.test.ts
|
||||
*
|
||||
* 验证 Viper 方言下内置 enumerate 的语义:
|
||||
* - enumerate(str) 调用类型为 enumerate[t.CChar](_T 按 for 原迭代逻辑绑定元素类型)
|
||||
* - `for i, ch in enumerate(str)` 中 i 为 t.CSizeT(size_t 索引)、ch 为迭代元素 t.CChar
|
||||
* - enumerate(str) 调用类型为 enumerate[char](_T 按 for 原迭代逻辑绑定元素类型)
|
||||
* - `for i, ch in enumerate(str)` 中 i 为 t.CSizeT(size_t 索引)、ch 为迭代元素 char
|
||||
* - 与 Python 声明(Iterable[_T] 协议、tuple[int, _T])的差异由 Viper 特判覆盖
|
||||
*
|
||||
* 运行:npx jest src/tests/viperEnumerate.test.ts --runInBand
|
||||
@@ -104,7 +104,7 @@ function collectForTargets(
|
||||
return { iterableTypes, targets };
|
||||
}
|
||||
|
||||
test('for i, ch in enumerate(kw_arg):i 为 t.CSizeT、ch 为 t.CChar', () => {
|
||||
test('for i, ch in enumerate(kw_arg):i 为 t.CSizeT、ch 为 char', () => {
|
||||
const source = `import t
|
||||
|
||||
def f(kw_arg: str) -> int:
|
||||
@@ -116,16 +116,16 @@ def f(kw_arg: str) -> int:
|
||||
|
||||
const { iterableTypes, targets } = collectForTargets(program, parseResults!);
|
||||
|
||||
// 1. enumerate 调用类型:元素类型按 for 原迭代逻辑(str → t.CChar)
|
||||
assert(iterableTypes.some((t) => t === 'enumerate[CChar]'), `实际: ${JSON.stringify(iterableTypes)}`);
|
||||
// 1. enumerate 调用类型:元素类型按 for 原迭代逻辑(str → char)
|
||||
assert(iterableTypes.some((t) => t === 'enumerate[char]'), `实际: ${JSON.stringify(iterableTypes)}`);
|
||||
|
||||
// 2. 索引 i 为 t.CSizeT(size_t)
|
||||
const iTypes = targets.get('i');
|
||||
assert(iTypes && iTypes.some((t) => t === 'CSizeT'), `i 应为 CSizeT,实际: ${JSON.stringify(iTypes)}`);
|
||||
|
||||
// 3. 元素 ch 为 t.CChar
|
||||
// 3. 元素 ch 为 char(str/bytes 迭代元素,与 s[i] / *s 统一)
|
||||
const chTypes = targets.get('ch');
|
||||
assert(chTypes && chTypes.some((t) => t === 'CChar'), `ch 应为 CChar,实际: ${JSON.stringify(chTypes)}`);
|
||||
assert(chTypes && chTypes.some((t) => t === 'char'), `ch 应为 char,实际: ${JSON.stringify(chTypes)}`);
|
||||
|
||||
program.dispose();
|
||||
serviceProvider.dispose();
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "vipeye",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vipeye",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"vipeye": "index.js",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "vipeye",
|
||||
"displayName": "Vipeye",
|
||||
"description": "Type checker for the Viper language",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "TermiNexus"
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Change Log
|
||||
|
||||
## 1.1.422
|
||||
|
||||
- `str` / `bytes` iteration now yields `char` as well: `for ch in s` and `Iterable` / `Iterator` argument inference (`enumerate`, `zip`, `map`, `filter`, `reversed`, `sorted`, `list()` …) bind the element type to `char`, matching subscript `s[i]` and dereference `*s`. The old `t.CChar`-aliased `int` construction is removed
|
||||
|
||||
## 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`
|
||||
- `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 and `Iterable` inference were unified in 1.1.422
|
||||
|
||||
## 1.1.420
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "vscode-vipeye",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vscode-vipeye",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mermaid": "^11.12.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "vipeye",
|
||||
"displayName": "Vipeye",
|
||||
"description": "VS Code language support for Viper (LSP client)",
|
||||
"version": "1.1.421",
|
||||
"version": "1.1.422",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
||||
Reference in new issue
Block a user