feat(vipeye-internal): 新增内置 double 类型(复刻 float,64 位浮点)
- typeshed builtins.vpi 增加 double 类定义(复刻 float 结构) - 内置 float<->double 按 C 浮点规则互转,int->double 无损 - 内置 double 与 t.CDouble 双向隐式转换 - viperGenericTypeVarCall 12/12 测试通过
This commit is contained in:
1 parent
ac08b01baa
commit
23cc75e444
3 files changed
+167
-3
No files matched your search
@@ -26592,6 +26592,30 @@ export function createTypeEvaluator(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Viper 扩展:内置 float ↔ double 隐式转换。
|
||||
// Viper 中内置 double(64 位浮点,定义复刻 float)与内置 float 按 C 浮点
|
||||
// 隐式转换规则互转:float → double 无损(32 位 → 64 位),
|
||||
// double → float 允许降级(64 位 → 32 位)。
|
||||
if (
|
||||
isClassInstance(destType) && ClassType.isBuiltIn(destType, 'double') &&
|
||||
isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'float')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
isClassInstance(destType) && ClassType.isBuiltIn(destType, 'float') &&
|
||||
isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'double')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// 整数 → double(整数位宽 32/64 均 <= 64 位浮点,无损)。
|
||||
if (
|
||||
isClassInstance(destType) && ClassType.isBuiltIn(destType, 'double') &&
|
||||
isClassInstance(srcType) && ClassType.isBuiltIn(srcType, 'int')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Viper 扩展:CEnum 子类 → int 隐式转换语义。
|
||||
// C 语言中 enum 值可以隐式转换为 int(如 int x = FR_OK)。
|
||||
// Viper 的 CEnum 子类(如 FRESULT)的成员(如 FRESULT.FR_OK)
|
||||
@@ -26607,19 +26631,20 @@ 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。
|
||||
if (
|
||||
isClassInstance(destType) && isCTypeSubclassType(destType) &&
|
||||
isClassInstance(srcType) && ClassType.isBuiltIn(srcType, ['int', 'float', 'str', 'bool', 'bytes'])
|
||||
isClassInstance(srcType) && ClassType.isBuiltIn(srcType, ['int', 'float', 'double', 'str', 'bool', 'bytes'])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Viper 扩展:CType 子类 -> Python 内置类型隐式转换(反向)。
|
||||
// CInt/CFloat/CChar 等 CType 子类在底层等价于 Python 内置类型,
|
||||
// 可隐式转换回 int/float/str/bool/bytes。
|
||||
// 可隐式转换回 int/float/str/bool/bytes(含 t.CDouble → 内置 double)。
|
||||
// 覆盖场景:CInt 值传给 int 形参(如 def __init__(self, w: int) 接收 CInt 实参)。
|
||||
if (
|
||||
isClassInstance(destType) && ClassType.isBuiltIn(destType, ['int', 'float', 'str', 'bool', 'bytes']) &&
|
||||
isClassInstance(destType) && ClassType.isBuiltIn(destType, ['int', 'float', 'double', 'str', 'bool', 'bytes']) &&
|
||||
isClassInstance(srcType) && isCTypeSubclassType(srcType)
|
||||
) {
|
||||
return true;
|
||||
|
||||
@@ -876,3 +876,71 @@ def use():
|
||||
}
|
||||
serviceProvider.dispose();
|
||||
});
|
||||
|
||||
test('Viper 内置 double 类型(复刻 float,64 位)可用', () => {
|
||||
const tempFile = new RealTempFile();
|
||||
const serviceProvider = createServiceProvider(createFromRealFileSystem(tempFile), new NullConsole(), tempFile);
|
||||
const projectRoot = UriEx.file(TRANSPYC_INCLUDES);
|
||||
const configOptions = new ConfigOptions(projectRoot);
|
||||
configOptions.internalTestMode = true;
|
||||
configOptions.initializeTypeCheckingMode('standard');
|
||||
|
||||
const execEnv = new ExecutionEnvironment(
|
||||
'python',
|
||||
projectRoot,
|
||||
configOptions.diagnosticRuleSet,
|
||||
configOptions.defaultPythonVersion,
|
||||
configOptions.defaultPythonPlatform,
|
||||
[projectRoot],
|
||||
/* skipNativeLibraries */ false,
|
||||
/* defaultDialect */ 'viper'
|
||||
);
|
||||
configOptions.executionEnvironments = [execEnv];
|
||||
|
||||
const code = `import t
|
||||
|
||||
def test_double():
|
||||
# float 字面量 → double(32 位 → 64 位,无损)
|
||||
d: double = 1.5
|
||||
# double 运算返回 double
|
||||
e: double = d * 2.0
|
||||
# double 构造
|
||||
f: double = double(3)
|
||||
# double + int → double(整数位宽 <= 64 位浮点,无损)
|
||||
g: double = d + 1
|
||||
# 内置 double → t.CDouble
|
||||
h: t.CDouble = d
|
||||
`;
|
||||
const testDir = path.join(__dirname, '__viper_double_test__');
|
||||
const fs = require('fs');
|
||||
fs.mkdirSync(testDir, { recursive: true });
|
||||
const testFile = path.join(testDir, 'double_type.vp');
|
||||
fs.writeFileSync(testFile, code, 'utf8');
|
||||
|
||||
try {
|
||||
const importResolver = new ImportResolver(serviceProvider, configOptions, new FullAccessHost(serviceProvider));
|
||||
const program = new Program(importResolver, configOptions, serviceProvider);
|
||||
const uri = UriEx.file(testFile);
|
||||
program.setTrackedFiles([uri]);
|
||||
while (program.analyze()) {
|
||||
// 循环
|
||||
}
|
||||
|
||||
const diagnostics = getDiagnostics(program, configOptions, uri);
|
||||
console.log('=== double_type.vp diagnostics ===');
|
||||
diagnostics.forEach((d) => console.log(` ${d}`));
|
||||
|
||||
// 期望没有任何错误级诊断:double 类型、运算、构造及 t.CDouble 转换均可用。
|
||||
const errors = diagnostics.filter((d) => d.startsWith('[category=0]'));
|
||||
assert.strictEqual(
|
||||
errors.length,
|
||||
0,
|
||||
`unexpected error diagnostics: ${JSON.stringify(diagnostics)}`
|
||||
);
|
||||
|
||||
program.dispose();
|
||||
} finally {
|
||||
fs.rmSync(testDir, { recursive: true, force: true });
|
||||
}
|
||||
serviceProvider.dispose();
|
||||
});
|
||||
@@ -434,6 +434,77 @@ class float:
|
||||
@classmethod
|
||||
def from_number(cls, number: float | SupportsIndex | SupportsFloat, /) -> Self: ...
|
||||
|
||||
@disjoint_base
|
||||
class double:
|
||||
"""double 类型(64 位浮点,定义复刻 float)。"""
|
||||
|
||||
def __new__(cls, x: ConvertibleToFloat = 0, /) -> Self: ...
|
||||
def as_integer_ratio(self) -> tuple[int, int]: ...
|
||||
def hex(self) -> str: ...
|
||||
def is_integer(self) -> bool: ...
|
||||
@classmethod
|
||||
def fromhex(cls, string: str, /) -> Self: ...
|
||||
@property
|
||||
def real(self) -> double: ...
|
||||
@property
|
||||
def imag(self) -> double: ...
|
||||
def conjugate(self) -> double: ...
|
||||
def __add__(self, value: double, /) -> double: ...
|
||||
def __sub__(self, value: double, /) -> double: ...
|
||||
def __mul__(self, value: double, /) -> double: ...
|
||||
def __floordiv__(self, value: double, /) -> double: ...
|
||||
def __truediv__(self, value: double, /) -> double: ...
|
||||
def __mod__(self, value: double, /) -> double: ...
|
||||
def __divmod__(self, value: double, /) -> tuple[double, double]: ...
|
||||
|
||||
@overload
|
||||
def __pow__(self, value: int, mod: None = None, /) -> double: ...
|
||||
@overload
|
||||
def __pow__(self, value: double, mod: None = None, /) -> Any: ...
|
||||
|
||||
def __radd__(self, value: double, /) -> double: ...
|
||||
def __rsub__(self, value: double, /) -> double: ...
|
||||
def __rmul__(self, value: double, /) -> double: ...
|
||||
def __rfloordiv__(self, value: double, /) -> double: ...
|
||||
def __rtruediv__(self, value: double, /) -> double: ...
|
||||
def __rmod__(self, value: double, /) -> double: ...
|
||||
def __rdivmod__(self, value: double, /) -> tuple[double, double]: ...
|
||||
|
||||
@overload
|
||||
def __rpow__(self, value: _PositiveInteger, mod: None = None, /) -> double: ...
|
||||
@overload
|
||||
def __rpow__(self, value: _NegativeInteger, mod: None = None, /) -> complex: ...
|
||||
@overload
|
||||
def __rpow__(self, value: double, mod: None = None, /) -> Any: ...
|
||||
|
||||
def __getnewargs__(self) -> tuple[double]: ...
|
||||
def __trunc__(self) -> int: ...
|
||||
def __ceil__(self) -> int: ...
|
||||
def __floor__(self) -> int: ...
|
||||
|
||||
@overload
|
||||
def __round__(self, ndigits: None = None, /) -> int: ...
|
||||
@overload
|
||||
def __round__(self, ndigits: SupportsIndex, /) -> double: ...
|
||||
|
||||
def __eq__(self, value: object, /) -> bool: ...
|
||||
def __ne__(self, value: object, /) -> bool: ...
|
||||
def __lt__(self, value: double, /) -> bool: ...
|
||||
def __le__(self, value: double, /) -> bool: ...
|
||||
def __gt__(self, value: double, /) -> bool: ...
|
||||
def __ge__(self, value: double, /) -> bool: ...
|
||||
def __neg__(self) -> double: ...
|
||||
def __pos__(self) -> double: ...
|
||||
def __int__(self) -> int: ...
|
||||
def __float__(self) -> double: ...
|
||||
def __abs__(self) -> double: ...
|
||||
def __hash__(self) -> int: ...
|
||||
def __bool__(self) -> bool: ...
|
||||
def __format__(self, format_spec: str, /) -> str: ...
|
||||
if sys.version_info >= (3, 14):
|
||||
@classmethod
|
||||
def from_number(cls, number: float | SupportsIndex | SupportsFloat, /) -> Self: ...
|
||||
|
||||
@disjoint_base
|
||||
class complex:
|
||||
# Python doesn't currently accept SupportsComplex for the second argument
|
||||
|
||||
Reference in new issue
Block a user