@@ -33,12 +33,13 @@ pub fn get_type_at_flow(
3333 }
3434 }
3535
36- let mut result_type = LuaType :: Unknown ;
36+ let result_type;
3737 let mut antecedent_flow_id = flow_id;
3838 loop {
3939 let flow_node = tree
4040 . get_flow_node ( antecedent_flow_id)
4141 . ok_or ( InferFailReason :: None ) ?;
42+
4243 match & flow_node. kind {
4344 FlowNodeKind :: Start | FlowNodeKind :: Unreachable => {
4445 result_type = get_var_ref_type ( db, cache, var_ref_id) ?;
@@ -49,10 +50,42 @@ pub fn get_type_at_flow(
4950 }
5051 FlowNodeKind :: BranchLabel | FlowNodeKind :: NamedLabel ( _) => {
5152 let multi_antecedents = get_multi_antecedents ( tree, flow_node) ?;
52- for flow_id in multi_antecedents {
53+
54+ // 在分支前获取原始类型
55+ let original_type = if let Some ( antecedent) = & flow_node. antecedent {
56+ match antecedent {
57+ crate :: FlowAntecedent :: Single ( single_id) => {
58+ get_type_at_flow ( db, tree, cache, root, var_ref_id, * single_id) ?
59+ }
60+ crate :: FlowAntecedent :: Multiple ( _) => {
61+ // 在 BranchLabel 中,多个 antecedent 需要获取共同的祖先
62+ get_var_ref_type ( db, cache, var_ref_id) ?
63+ }
64+ }
65+ } else {
66+ get_var_ref_type ( db, cache, var_ref_id) ?
67+ } ;
68+
69+ let mut branch_types = Vec :: new ( ) ;
70+
71+ for & flow_id in & multi_antecedents {
5372 let branch_type = get_type_at_flow ( db, tree, cache, root, var_ref_id, flow_id) ?;
54- result_type = TypeOps :: Union . apply ( db , & result_type , & branch_type) ;
73+ branch_types . push ( branch_type) ;
5574 }
75+
76+ // 分析类型覆盖
77+ let result_type_analysis = analyze_branch_coverage (
78+ & original_type,
79+ & branch_types,
80+ db,
81+ tree,
82+ cache,
83+ root,
84+ var_ref_id,
85+ & multi_antecedents,
86+ ) ?;
87+
88+ result_type = result_type_analysis;
5689 break ;
5790 }
5891 FlowNodeKind :: DeclPosition ( position) => {
@@ -237,3 +270,138 @@ fn get_type_at_assign_stat(
237270
238271 Ok ( ResultTypeOrContinue :: Continue )
239272}
273+
274+ // 分析分支覆盖率, 确定原始类型中哪些部分被赋值覆盖
275+ fn analyze_branch_coverage (
276+ original_type : & LuaType ,
277+ branch_types : & [ LuaType ] ,
278+ db : & DbIndex ,
279+ tree : & FlowTree ,
280+ cache : & mut LuaInferCache ,
281+ root : & LuaChunk ,
282+ var_ref_id : & VarRefId ,
283+ flow_ids : & [ FlowId ] ,
284+ ) -> Result < LuaType , InferFailReason > {
285+ if branch_types. is_empty ( ) {
286+ return Ok ( original_type. clone ( ) ) ;
287+ }
288+
289+ // 检查哪些分支实际上有赋值
290+ let mut assignment_branches = Vec :: new ( ) ;
291+ let mut non_assignment_branches = Vec :: new ( ) ;
292+
293+ for ( i, & flow_id) in flow_ids. iter ( ) . enumerate ( ) {
294+ let branch_type = & branch_types[ i] ;
295+
296+ // 检查这个分支是否有赋值, 通过检查类型是否显著变化
297+ let has_assignment = !types_are_equivalent ( branch_type, original_type)
298+ && has_assignment_in_branch ( db, tree, cache, root, var_ref_id, flow_id) ?;
299+
300+ if has_assignment {
301+ assignment_branches. push ( branch_type. clone ( ) ) ;
302+ } else {
303+ non_assignment_branches. push ( branch_type. clone ( ) ) ;
304+ }
305+ }
306+
307+ if !assignment_branches. is_empty ( ) {
308+ // 检查所有赋值分支是否都是相同的类型
309+ let first_assignment_type = & assignment_branches[ 0 ] ;
310+ let all_assignments_same = assignment_branches
311+ . iter ( )
312+ . all ( |t| types_are_equivalent ( t, first_assignment_type) ) ;
313+
314+ if all_assignments_same && assignment_branches. len ( ) >= 2 {
315+ // 多个分支具有相同的赋值类型, 表明完全覆盖
316+ return Ok ( first_assignment_type. clone ( ) ) ;
317+ }
318+ }
319+
320+ // 回退到原始行为: 合并所有分支类型
321+ let mut result_type = LuaType :: Unknown ;
322+ let mut has_any_type = false ;
323+
324+ for branch_type in branch_types {
325+ if !has_any_type {
326+ result_type = branch_type. clone ( ) ;
327+ has_any_type = true ;
328+ } else {
329+ result_type = TypeOps :: Union . apply ( db, & result_type, branch_type) ;
330+ }
331+ }
332+
333+ Ok ( result_type)
334+ }
335+
336+ // 检查分支是否包含对目标变量的赋值
337+ fn has_assignment_in_branch (
338+ db : & DbIndex ,
339+ tree : & FlowTree ,
340+ cache : & mut LuaInferCache ,
341+ root : & LuaChunk ,
342+ var_ref_id : & VarRefId ,
343+ start_flow_id : FlowId ,
344+ ) -> Result < bool , InferFailReason > {
345+ let mut current_flow_id = start_flow_id;
346+
347+ // 遍历流向后看是否在这个分支中有赋值
348+ loop {
349+ let flow_node = tree
350+ . get_flow_node ( current_flow_id)
351+ . ok_or ( InferFailReason :: None ) ?;
352+
353+ match & flow_node. kind {
354+ FlowNodeKind :: Assignment ( assign_ptr) => {
355+ let assign_stat = assign_ptr. to_node ( root) . ok_or ( InferFailReason :: None ) ?;
356+ let result_or_continue = get_type_at_assign_stat (
357+ db,
358+ tree,
359+ cache,
360+ root,
361+ var_ref_id,
362+ flow_node,
363+ assign_stat,
364+ ) ?;
365+
366+ if let ResultTypeOrContinue :: Result ( _) = result_or_continue {
367+ return Ok ( true ) ;
368+ }
369+
370+ // 继续检查 antecedents
371+ current_flow_id = get_single_antecedent ( tree, flow_node) ?;
372+ }
373+ FlowNodeKind :: TrueCondition ( _) | FlowNodeKind :: FalseCondition ( _) => {
374+ // 继续通过条件节点
375+ current_flow_id = get_single_antecedent ( tree, flow_node) ?;
376+ }
377+ FlowNodeKind :: BranchLabel | FlowNodeKind :: NamedLabel ( _) => {
378+ // 到达另一个分支点, 停止这里
379+ return Ok ( false ) ;
380+ }
381+ FlowNodeKind :: Start | FlowNodeKind :: Unreachable => {
382+ // 到达开始没有找到赋值
383+ return Ok ( false ) ;
384+ }
385+ FlowNodeKind :: DeclPosition ( _) => {
386+ // 到达声明, 停止这里
387+ return Ok ( false ) ;
388+ }
389+ _ => {
390+ // 继续检查 antecedents 对于其他 flow node 类型
391+ current_flow_id = get_single_antecedent ( tree, flow_node) ?;
392+ }
393+ }
394+ }
395+ }
396+
397+ // 检查两个类型是否等价
398+ fn types_are_equivalent ( a : & LuaType , b : & LuaType ) -> bool {
399+ match ( a, b) {
400+ ( LuaType :: Union ( a_union) , LuaType :: Union ( b_union) ) => {
401+ let a_types = a_union. into_vec ( ) ;
402+ let b_types = b_union. into_vec ( ) ;
403+ a_types. len ( ) == b_types. len ( ) && a_types. iter ( ) . all ( |t| b_types. contains ( t) )
404+ }
405+ _ => a == b,
406+ }
407+ }
0 commit comments