diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index b04946c..c826def 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -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)但被调名无法解析为标量类型:明确的类型意图却无法 diff --git a/App/lib/core/Gen/Class/ClassGenGeneric.vp b/App/lib/core/Gen/Class/ClassGenGeneric.vp index 6a601b1..1407a2b 100644 --- a/App/lib/core/Gen/Class/ClassGenGeneric.vp +++ b/App/lib/core/Gen/Class/ClassGenGeneric.vp @@ -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*,