fix(generic): 泛型类构造 Call 实参推断同步收紧,抽出共用精确映射

CallGenCtor._infer_generic_ctor_type_arg 的 Call 分支此前与泛型函数路径同款名字子串猜测(含 Int→int、Float→double),把 CUInt64T/CInt16T 静默归成 int=i32、CFloat32T 猜成 double。改为:把被调表达式交给注解解析器,命中标量才据精确位宽映射;非标量/不可解析仍 fail-fast(保持原有"明确的类型意图却无法解析"报错)。

新增 ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty 作为两处共用的唯一入口(内部走 _infer_scalar_type_name_from_spec),泛型函数路径一并改为调用它,消除重复的 arena/SpecFromLLVMType 样板,保证两处同口径。
This commit is contained in:
TermiNexus committed 2026-10-03 15:51:12 +08:00
1 parent 9a80f1df6c
commit 28b7437e21
2 files changed
+34 -32

No files matched your search

+16 -29
View File
@@ -847,35 +847,22 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if k == ast.ASTKind.Call:
cl_f: ast.Call* = ast.Call*(arg_node)
if cl_f.func is not None:
if cl_f.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name* = ast.Name*(cl_f.func)
if fn_nm.id is not None:
# 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt
# 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float
# 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。
if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None:
return "double"
# char 内置类型(char(x) 或含 "Char" 的 t/c 类名:CChar/UChar 等)
# → "char",与 float/double 并列(此前归 int 组丢失 i8 语义)
if string.strcmp(fn_nm.id, "char") == 0 or string.strstr(fn_nm.id, "Char") is not None:
return "char"
if string.strcmp(fn_nm.id, "int") == 0 \
or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \
or string.strstr(fn_nm.id, "Short") is not None \
or string.strstr(fn_nm.id, "Long") is not None:
return "int"
elif cl_f.func.kind() == ast.ASTKind.Attribute:
fn_at: ast.Attribute* = ast.Attribute*(cl_f.func)
if fn_at.attr is not None:
if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None:
return "double"
# char 内置类型(char(x) 等含 "Char" 的类名)→ "char"
if string.strstr(fn_at.attr, "Char") is not None:
return "char"
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
return "int"
# 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析,
# fail-fast(返回 None ⇒ 调用方 fail-fast)。
# 只认「被调名本身可解析为**标量类型**」的转换调用:把被调表达式交给
# 注解解析器解析,命中标量即据其**精确位宽**经
# ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty(唯一真源)映射。
# 彻底移除原按名字子串猜测(含 Int→int 等):它把 CUInt64T/CInt16T
# 一律归成 int=i32(静默窄化/扩宽),CFloat32T 猜成 double。
# 与泛型函数路径 ClassGenGeneric._infer_generic_func_type_arg 同口径。
fk_c: int = cl_f.func.kind()
if (fk_c == ast.ASTKind.Name or fk_c == ast.ASTKind.Attribute) and trans is not None:
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)
if ta_c is not None:
return ta_c
# 类型转换调用(Call)但被调名无法解析为标量类型:明确的类型意图却无法
# 解析,fail-fast(返回 None ⇒ 调用方 fail-fast)。
self.Gen.TypeGenErr.fatal_error(arg_node, f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", "TypeError")
return None
# 普通变量(Name)实参:取变量条目的注解类名(与形参定义/AnnAssign 经
+18 -3
View File
@@ -407,9 +407,7 @@ 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:
arena_c: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
if arena_c is not None:
return self._infer_scalar_type_name_from_spec(pool, TSpec.SpecFromLLVMType(arena_c, cty_f))
return self.infer_scalar_type_arg_from_llvm_ty(pool, cty_f)
return None
return None
@@ -446,6 +444,23 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
if string.strcmp(buf, "i32") == 0: return "int"
return None
def infer_scalar_type_arg_from_llvm_ty(self, pool: memhub.MemBuddy*,
ty: llvmlite.LLVMType*) -> str:
"""LLVM **标量**类型 → 泛型类型实参票名(精确位宽;非标量返回 None)
泛型函数(ClassGenGeneric._infer_generic_func_type_arg)与泛型类构造
(CallGenCtor._infer_generic_ctor_type_arg)的 Call 实参推断共用,保证
"转换调用实参 → 类型实参" 两处同口径(唯一真源
_infer_scalar_type_name_from_spec)。非标量(结构体/指针/数组/函数)返回
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))
def _clone_funcdef_for_spec(self, pool: memhub.MemBuddy*,
fd: ast.FunctionDef*,
spec_base: str,