fix(match): case A | B 的 OR 模式注册全部备选(switch 仅取首个)
_handle_simple_match 的 MatchOr 分支此前只把 pats[0] 译成 case 值 → switch value: case 1 | 2 中 2 落 default(LogicFlowTest SwitchMultiValueTest(2) != 10)。改为按臂记录 MatchOr 节点,建 sw 链时逐备选 new_switch_case 挂同一 body(等价 C 的 case 1: case 2:);_handle_guarded_simple_match 同款:cond 改为各备选 subj==cv 的 OR 再与 guard 取与。非 MatchOr 路径逐字不变;非值备选改为 fail-fast(原为静默丢弃)。
This commit is contained in:
1 parent
3b465121cd
commit
f2b65f57ec
1 file changed
+110
-35
@@ -1352,7 +1352,11 @@ novirtual class MatchGenMixin:
|
||||
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
|
||||
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):`case 1 | 2:` 需为
|
||||
# 每个备选各产出一个 switch case 值(同一 body BB),故此处记录节点,
|
||||
# 建 sw 链时逐备选展开。非 MatchOr 恒为 0,走原单 cv 路径逐字不变。
|
||||
mo_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None or mo_arr is None:
|
||||
# fail-fast: match 分派数组分配失败
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
|
||||
@@ -1382,6 +1386,9 @@ novirtual class MatchGenMixin:
|
||||
|
||||
is_def: int = 0
|
||||
cv: llvmlite.Value* = None
|
||||
# MatchOr 臂节点(非 MatchOr 保持 None):pass1 只记录,真正的
|
||||
# 逐备选 case 值在建 sw 链时产出,保证 `case 1 | 2:` 两个值都命中同一 body。
|
||||
or_node: ast.AST* = None
|
||||
|
||||
if pat is not None:
|
||||
pk: int = pat.kind()
|
||||
@@ -1400,14 +1407,8 @@ novirtual class MatchGenMixin:
|
||||
has_default = 1
|
||||
default_case_node = case_node
|
||||
elif pk == ast.ASTKind.MatchOr:
|
||||
mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat)
|
||||
pats: list[ast.AST*]* = mo.patterns
|
||||
if pats is not None and len(pats) > 0:
|
||||
first_pat: ast.AST* = pats.get(0)
|
||||
if first_pat is not None \
|
||||
and first_pat.kind() == ast.ASTKind.MatchValue:
|
||||
mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(first_pat)
|
||||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans)
|
||||
# 记录整节点:备选在建 sw 链处逐个数展开,不再只取第 0 个。
|
||||
or_node = pat
|
||||
elif pk == ast.ASTKind.MatchClass:
|
||||
# 本路径(非 REnum 分派)不为 class-pattern 臂产出 case 值 → 该臂被
|
||||
# 静默丢弃、臂体不可达。若该 class-pattern 确实指向已注册 REnum
|
||||
@@ -1430,23 +1431,62 @@ novirtual class MatchGenMixin:
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
|
||||
# 本臂占用的收集槽位:collected 随后自增;is_def==0 时上方已保证未越界
|
||||
cur_slot: int = collected
|
||||
if collected < MAX_MATCH_CASES:
|
||||
bb_arr[collected] = sizet(bb)
|
||||
cv_arr[collected] = sizet(cv)
|
||||
def_arr[collected] = is_def
|
||||
nb_arr[collected] = nb
|
||||
bb_arr[cur_slot] = sizet(bb)
|
||||
cv_arr[cur_slot] = sizet(cv)
|
||||
def_arr[cur_slot] = is_def
|
||||
nb_arr[cur_slot] = nb
|
||||
mo_arr[cur_slot] = sizet(or_node)
|
||||
collected = collected + 1
|
||||
|
||||
if is_def == 0 and cv is not None:
|
||||
sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb)
|
||||
if sc is not None:
|
||||
if sw_head is None:
|
||||
sw_head = sc
|
||||
sw_tail = sc
|
||||
else:
|
||||
sw_tail.Next = sc
|
||||
sw_tail = sc
|
||||
sw_count = sw_count + 1
|
||||
if is_def == 0:
|
||||
mo_addr: sizet = mo_arr[cur_slot]
|
||||
if mo_addr != 0:
|
||||
# MatchOr 臂:为每个备选各产出一个 case 值,全部指向同一 bb
|
||||
# (等价 C 的 `case 1: case 2:`,共享 body)。非 MatchValue/
|
||||
# MatchSingleton 备选无法产出值,fail-fast 不得静默丢弃。
|
||||
mo2: rawptr[ast.MatchOr] = (rawptr[ast.MatchOr])(mo_addr)
|
||||
pats2: list[ast.AST*]* = mo2.patterns
|
||||
if pats2 is None or len(pats2) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "switch OR 模式无备选子模式", "TypeError")
|
||||
pats2_n: sizet = len(pats2)
|
||||
pats2_i: int = 0
|
||||
while pats2_i < pats2_n:
|
||||
alt_pat: ast.AST* = pats2.get(pats2_i)
|
||||
if alt_pat is not None:
|
||||
alt_cv: llvmlite.Value* = None
|
||||
if alt_pat.kind() == ast.ASTKind.MatchValue:
|
||||
alt_mv: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(alt_pat)
|
||||
alt_cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, alt_mv.value,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
elif alt_pat.kind() == ast.ASTKind.MatchSingleton:
|
||||
# None -> 0(与单值/守卫路径同口径)
|
||||
alt_cv = llvmlite.const_int32(pool, 0)
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(alt_pat, "switch OR 模式备选不是值模式", "TypeError")
|
||||
if alt_cv is not None:
|
||||
sc2: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, alt_cv, bb)
|
||||
if sc2 is not None:
|
||||
if sw_head is None:
|
||||
sw_head = sc2
|
||||
sw_tail = sc2
|
||||
else:
|
||||
sw_tail.Next = sc2
|
||||
sw_tail = sc2
|
||||
sw_count = sw_count + 1
|
||||
pats2_i = pats2_i + 1
|
||||
elif cv is not None:
|
||||
sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb)
|
||||
if sc is not None:
|
||||
if sw_head is None:
|
||||
sw_head = sc
|
||||
sw_tail = sc
|
||||
else:
|
||||
sw_tail.Next = sc
|
||||
sw_tail = sc
|
||||
sw_count = sw_count + 1
|
||||
|
||||
i = i + 1
|
||||
|
||||
@@ -1612,8 +1652,12 @@ novirtual class MatchGenMixin:
|
||||
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||||
mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):check 链需把
|
||||
# `case 1 | 2` 变成各备选 subj_val == cv_i 的 OR,故此处记录节点,
|
||||
# 发射 check 时逐备选展开取 OR。非 MatchOr 恒为 0,走原单 cv 路径不变。
|
||||
or_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
if check_arr is None or body_arr is None or def_arr is None \
|
||||
or nb_arr is None or mc_arr is None or cv_arr is None:
|
||||
or nb_arr is None or mc_arr is None or cv_arr is None or or_arr is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
collected: int = 0
|
||||
has_default: int = 0
|
||||
@@ -1636,6 +1680,9 @@ novirtual class MatchGenMixin:
|
||||
gnode0: ast.AST* = mc.guard
|
||||
is_def: int = 0
|
||||
cv: llvmlite.Value* = None
|
||||
# MatchOr 臂节点(非 MatchOr 保持 None):pass1 只记录,check 发射时
|
||||
# 逐备选展开成 subj_val == cv_i 的 OR,不再只看第 0 个备选。
|
||||
or_node: ast.AST* = None
|
||||
if pat is not None:
|
||||
pk: int = pat.kind()
|
||||
if pk == ast.ASTKind.MatchValue:
|
||||
@@ -1653,16 +1700,8 @@ novirtual class MatchGenMixin:
|
||||
# ma.pattern is None 且 guard 非空 → 带 guard 的通配臂:条件恒真
|
||||
# 再与 guard 取与(见发射阶段),不当作 default
|
||||
elif pk == ast.ASTKind.MatchOr:
|
||||
# MatchOr:取第一个 MatchValue 作比较(与 _handle_simple_match 的
|
||||
# switch 路径同口径,其余子模式在 guard 链中不展开)
|
||||
mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat)
|
||||
pats_o: list[ast.AST*]* = mo.patterns
|
||||
if pats_o is not None and len(pats_o) > 0:
|
||||
fp: ast.AST* = pats_o.get(0)
|
||||
if fp is not None and fp.kind() == ast.ASTKind.MatchValue:
|
||||
mv2: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](fp)
|
||||
cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv2.value,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
# 记录整节点:check 发射时逐备选展开为 OR(见 step 4)
|
||||
or_node = pat
|
||||
else:
|
||||
# 禁止静默兜底:guard 分支只支持 值/None/通配/或 模式
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "guard 分支不支持的 case 模式", "TypeError")
|
||||
@@ -1686,6 +1725,7 @@ novirtual class MatchGenMixin:
|
||||
nb_arr[collected] = nb
|
||||
mc_arr[collected] = sizet(mc)
|
||||
cv_arr[collected] = sizet(cv)
|
||||
or_arr[collected] = sizet(or_node)
|
||||
collected = collected + 1
|
||||
i = i + 1
|
||||
|
||||
@@ -1710,8 +1750,43 @@ novirtual class MatchGenMixin:
|
||||
mc2: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_arr[ci])
|
||||
# 值条件:subj_val == case值(通配臂无 case 值 → cond 保持 None=恒真)
|
||||
cond: llvmlite.Value* = None
|
||||
or_addr: sizet = or_arr[ci]
|
||||
cv_addr: sizet = cv_arr[ci]
|
||||
if cv_addr != 0:
|
||||
if or_addr != 0:
|
||||
# MatchOr 臂:cond = (subj_val == cv_0) OR (subj_val == cv_1) OR ...
|
||||
# 各备选逐一比较后取 OR(非 MatchValue/MatchSingleton 备选无法产出
|
||||
# 值 → fail-fast,不静默丢弃)。
|
||||
mo4: rawptr[ast.MatchOr] = (rawptr[ast.MatchOr])(or_addr)
|
||||
pats4: list[ast.AST*]* = mo4.patterns
|
||||
if pats4 is None or len(pats4) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式无备选子模式", "TypeError")
|
||||
pats4_n: sizet = len(pats4)
|
||||
pats4_i: int = 0
|
||||
while pats4_i < pats4_n:
|
||||
alt_pat2: ast.AST* = pats4.get(pats4_i)
|
||||
if alt_pat2 is not None:
|
||||
alt_cv2: llvmlite.Value* = None
|
||||
if alt_pat2.kind() == ast.ASTKind.MatchValue:
|
||||
alt_mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(alt_pat2)
|
||||
alt_cv2 = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, alt_mv2.value,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
elif alt_pat2.kind() == ast.ASTKind.MatchSingleton:
|
||||
# None -> 0(与单值路径同口径)
|
||||
alt_cv2 = llvmlite.const_int32(pool, 0)
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(alt_pat2, "guard OR 模式备选不是值模式", "TypeError")
|
||||
if alt_cv2 is not None:
|
||||
cc: llvmlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, alt_cv2)
|
||||
if cc is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match OR 备选值比较失败", "TypeError")
|
||||
if cond is None:
|
||||
cond = cc
|
||||
else:
|
||||
cond = llvmlite.build_or(builder, cond, cc)
|
||||
pats4_i = pats4_i + 1
|
||||
if cond is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式未能产出任何比较条件", "TypeError")
|
||||
elif cv_addr != 0:
|
||||
cv2: llvmlite.Value* = (llvmlite.Value*)(cv_addr)
|
||||
c1: llvmlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, cv2)
|
||||
if c1 is None:
|
||||
|
||||
Reference in new issue
Block a user