feat(generic): 泛型实参推断为无裸名别名的整型位宽补精确票名
- _infer_scalar_type_name_from_spec 支持 i64/i16 -> t.CUInt64T/t.CInt64T、t.CUInt16T/t.CInt16T;符号性未知时不猜(返回 None) - infer_scalar_type_arg_from_llvm_ty 增加 sign 参数:LLVM 类型层无法区分 iN/uN,符号性由被调名源码文本经 SpecSignFromTypeNameSpan 判定 - 泛型函数与泛型类构造两处 Call 推断同步传符号性,修复 GenericOopTest fxi2 第 3 个类型实参(CUInt64T)推断失败
This commit is contained in:
1 parent
ddb1e6cc2a
commit
21436b2690
2 files changed
+65
-12
No files matched your search
@@ -9,7 +9,8 @@ import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
from . import CallGenBase
|
||||
|
||||
@@ -858,7 +859,17 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
cty_c: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, cl_f.func, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if cty_c is not None:
|
||||
ta_c: str = self.Gen.ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty(pool, cty_c)
|
||||
# 符号性从被调名源码文本取(LLVM 层 iN/uN 同形):决定
|
||||
# CUInt64T/CInt16T 这类无裸名别名位宽发 t.CUInt64T / t.CInt64T。
|
||||
callee_txt_c: str = None
|
||||
if fk_c == ast.ASTKind.Name:
|
||||
callee_txt_c = ast.Name*(cl_f.func).id
|
||||
else:
|
||||
callee_txt_c = ast.Attribute*(cl_f.func).attr
|
||||
sign_c: int = TSpec.TS_SIGN_UNKNOWN
|
||||
if callee_txt_c is not None:
|
||||
sign_c = TSpec.SpecSignFromTypeNameSpan(callee_txt_c, 0, string.strlen(callee_txt_c))
|
||||
ta_c: str = self.Gen.ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty(pool, cty_c, sign_c)
|
||||
if ta_c is not None:
|
||||
return ta_c
|
||||
# 类型转换调用(Call)但被调名无法解析为标量类型:明确的类型意图却无法
|
||||
|
||||
@@ -22,6 +22,8 @@ define GENERIC_SPEC_MAX_DEPTH = 64
|
||||
define GENERIC_TEMPLATE_MAX = 512
|
||||
# 泛型特化缓存表容量
|
||||
define SPEC_CACHE_MAX = 512
|
||||
# 符号性哨兵:表示"取自 Spec.IsSigned"(区别于 TSpec.TS_SIGN_* 三值)
|
||||
define SIGN_FROM_SPEC = -2
|
||||
|
||||
# ============================================================
|
||||
# ClassGenGeneric - 泛型模板注册/特化/克隆
|
||||
@@ -407,24 +409,44 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
cty_f: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, cl_f.func, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if cty_f is not None:
|
||||
return self.infer_scalar_type_arg_from_llvm_ty(pool, cty_f)
|
||||
# 符号性只能从**被调名源码文本**取(LLVM 层 iN/uN 同形,
|
||||
# SpecFromLLVMType 恒给 SIGNED):CUInt64T/CInt16T 这类
|
||||
# 无裸名别名的位宽必须靠它决定发 t.CUInt64T 还是 t.CInt64T。
|
||||
callee_txt: str = None
|
||||
if fk_f == ast.ASTKind.Name:
|
||||
callee_txt = ast.Name*(cl_f.func).id
|
||||
else:
|
||||
callee_txt = ast.Attribute*(cl_f.func).attr
|
||||
sign_f: int = TSpec.TS_SIGN_UNKNOWN
|
||||
if callee_txt is not None:
|
||||
sign_f = TSpec.SpecSignFromTypeNameSpan(callee_txt, 0, string.strlen(callee_txt))
|
||||
return self.infer_scalar_type_arg_from_llvm_ty(pool, cty_f, sign_f)
|
||||
return None
|
||||
return None
|
||||
|
||||
def _infer_scalar_type_name_from_spec(self, pool: memhub.MemBuddy*,
|
||||
sp: TSpec.TypeSpec*) -> str:
|
||||
sp: TSpec.TypeSpec*,
|
||||
sign_override: int = SIGN_FROM_SPEC) -> str:
|
||||
"""从变量的 TypeSpec 反推可解析的内建标量类型名
|
||||
|
||||
仅覆盖 extract_class_name_from_annotation 会跳过的内建标量
|
||||
(str/char/bytes/bool/float/double 的 SourceName 为 None):按 LLVM
|
||||
形态映射为源码可解析名(double/float/int/char/bool)。指针/结构体返回
|
||||
None(交由注解来源名路径处理;此处不做猜测,避免错特化)。
|
||||
形态映射为源码可解析名。指针/结构体返回 None(交由注解来源名路径处理;
|
||||
此处不做猜测,避免错特化)。
|
||||
|
||||
**只映射"位宽精确对应到某个裸名"的形态**(i1→bool、i8→char、i32→int、
|
||||
f32→float、f64→double)。i16/i64/f16 在 Viper 没有等位宽的裸名别名
|
||||
(裸 int=int32、裸 float=float32),映射过去会静默窄化/扩宽位宽
|
||||
(i64→int 即 i64→i32,直接改变 ABI 与数据),违反"禁止静默默认/兜底"
|
||||
原则 ⇒ 一律返回 None,由调用方汇总后 fail-fast 提示显式标注。
|
||||
f32→float、f64→double)。i16/i64 在 Viper 没有等位宽的裸名别名(裸
|
||||
int=int32、裸 float=float32),映射到 int 会静默窄化/扩宽位宽(i64→int
|
||||
即 i64→i32,直接改变 ABI 与数据)⇒ 改为发**精确位宽票名**
|
||||
t.CUInt64T/t.CInt64T、t.CUInt16T/t.CInt16T(可被 _parse_type_string
|
||||
解析),但**必须先知道符号性**:符号性未知时不猜(返回 None),由调用方
|
||||
汇总后 fail-fast。
|
||||
|
||||
符号性来源(sign_override):
|
||||
- SIGN_FROM_SPEC(默认):读 sp.IsSigned(注解侧 Spec 经
|
||||
SpecWithSign 写入,可信);
|
||||
- 显式 TS_SIGN_*:由调用方给出(LLVM 类型路径符号性在 LLVM 层已丢失,
|
||||
只能由**被调名文本**经 TSpec.SpecSignFromTypeName 判定)。
|
||||
"""
|
||||
if pool is None or sp is None: return None
|
||||
buf: str = pool.alloc(32)
|
||||
@@ -437,15 +459,30 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# "无法从实参推断泛型函数 ... 禁止静默默认 int"。
|
||||
if TSpec.SpecToLLVMText(sp, buf, 32) != 0:
|
||||
return None
|
||||
sign: int = sign_override
|
||||
if sign == SIGN_FROM_SPEC:
|
||||
# LLVM 层 SpecFromLLVMType 恒给 TS_SIGN_SIGNED(无法区分 iN/uN),
|
||||
# 故仅注解侧 Spec(经 SpecWithSign)可信任此字段。
|
||||
sign = sp.IsSigned
|
||||
if string.strcmp(buf, "double") == 0: return "double"
|
||||
if string.strcmp(buf, "float") == 0: return "float"
|
||||
if string.strcmp(buf, "i1") == 0: return "bool"
|
||||
if string.strcmp(buf, "i8") == 0: return "char"
|
||||
if string.strcmp(buf, "i32") == 0: return "int"
|
||||
# 无裸名别名的整型位宽 → 精确位宽票名(符号性未知则不猜)
|
||||
if string.strcmp(buf, "i64") == 0:
|
||||
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt64T"
|
||||
if sign == TSpec.TS_SIGN_SIGNED: return "t.CInt64T"
|
||||
return None
|
||||
if string.strcmp(buf, "i16") == 0:
|
||||
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt16T"
|
||||
if sign == TSpec.TS_SIGN_SIGNED: return "t.CInt16T"
|
||||
return None
|
||||
return None
|
||||
|
||||
def infer_scalar_type_arg_from_llvm_ty(self, pool: memhub.MemBuddy*,
|
||||
ty: llvmlite.LLVMType*) -> str:
|
||||
ty: llvmlite.LLVMType*,
|
||||
sign: int) -> str:
|
||||
"""LLVM **标量**类型 → 泛型类型实参票名(精确位宽;非标量返回 None)
|
||||
|
||||
泛型函数(ClassGenGeneric._infer_generic_func_type_arg)与泛型类构造
|
||||
@@ -453,13 +490,18 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"转换调用实参 → 类型实参" 两处同口径(唯一真源
|
||||
_infer_scalar_type_name_from_spec)。非标量(结构体/指针/数组/函数)返回
|
||||
None ⇒ 调用方不据此推断(宁缺毋错,不按名字子串猜)。
|
||||
|
||||
sign:LLVM 类型层无法区分 iN/uN(SpecFromLLVMType 恒给 TS_SIGN_SIGNED)
|
||||
⇒ 无符号性必须由调用方从**被调名源码文本**经 TSpec.SpecSignFromTypeName
|
||||
判定后传入;未知传 TSpec.TS_SIGN_UNKNOWN(此时 i16/i64 这类无裸名别名的
|
||||
位宽推不出,本函数返回 None)。
|
||||
"""
|
||||
if pool is None or ty is None:
|
||||
return None
|
||||
arena: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
|
||||
if arena is None:
|
||||
return None
|
||||
return self._infer_scalar_type_name_from_spec(pool, TSpec.SpecFromLLVMType(arena, ty))
|
||||
return self._infer_scalar_type_name_from_spec(pool, TSpec.SpecFromLLVMType(arena, ty), sign)
|
||||
|
||||
def _clone_funcdef_for_spec(self, pool: memhub.MemBuddy*,
|
||||
fd: ast.FunctionDef*,
|
||||
|
||||
Reference in new issue
Block a user