diff --git a/src/compiler/crystal/semantic/main_visitor.cr b/src/compiler/crystal/semantic/main_visitor.cr index 0e6826e72be7..0c3ddebf90eb 100644 --- a/src/compiler/crystal/semantic/main_visitor.cr +++ b/src/compiler/crystal/semantic/main_visitor.cr @@ -1887,85 +1887,88 @@ module Crystal # - Don't use the type of a branch that is unreachable (ends with return, # break or with a call that is NoReturn) def merge_if_vars(node, cond_vars, then_vars, else_vars, before_then_vars, before_else_vars, then_unreachable, else_unreachable) - all_vars_names = Set(String).new - then_vars.each_key do |name| - all_vars_names << name - end - else_vars.each_key do |name| - all_vars_names << name + then_vars.each do |name, then_var| + else_var = else_vars[name]? + + merge_if_var(name, node, cond_vars, then_var, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable) end - all_vars_names.each do |name| - cond_var = cond_vars[name]? - then_var = then_vars[name]? - before_then_var = before_then_vars[name]? - else_var = else_vars[name]? - before_else_var = before_else_vars[name]? + else_vars.each do |name, else_var| + next if then_vars.has_key?(name) - # Check whether the var didn't change at all - next if then_var.same?(else_var) + merge_if_var(name, node, cond_vars, nil, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable) + end + end - if_var = MetaVar.new(name) + def merge_if_var(name, node, cond_vars, then_var, else_var, before_then_vars, before_else_vars, then_unreachable, else_unreachable) + # Check whether the var didn't change at all + return if then_var.same?(else_var) - # Only copy `nil_if_read` from each branch if it's not unreachable - then_var_nil_if_read = !then_unreachable && then_var.try(&.nil_if_read?) - else_var_nil_if_read = !else_unreachable && else_var.try(&.nil_if_read?) + cond_var = cond_vars[name]? - if_var.nil_if_read = !!(then_var_nil_if_read || else_var_nil_if_read) + # Only copy `nil_if_read` from each branch if it's not unreachable + then_var_nil_if_read = !then_unreachable && then_var.try(&.nil_if_read?) + else_var_nil_if_read = !else_unreachable && else_var.try(&.nil_if_read?) + if_var_nil_if_read = !!(then_var_nil_if_read || else_var_nil_if_read) - # Check if no types were changes in either then 'then' and 'else' branches - if cond_var && then_var.same?(before_then_var) && else_var.same?(before_else_var) && !then_unreachable && !else_unreachable - cond_var.nil_if_read = if_var.nil_if_read? + # Check if no types were changes in either then 'then' and 'else' branches + if cond_var && !then_unreachable && !else_unreachable + if then_var.same?(before_then_vars[name]?) && + else_var.same?(before_else_vars[name]?) + cond_var.nil_if_read = if_var_nil_if_read @vars[name] = cond_var - next + return end + end - if then_var && else_var - if then_unreachable - if_var.bind_to conditional_no_return(node.then, then_var) - else - if_var.bind_to then_var - end + if_var = MetaVar.new(name) + if_var.nil_if_read = if_var_nil_if_read - if else_unreachable - if_var.bind_to conditional_no_return(node.else, else_var) - else - if_var.bind_to else_var - end - elsif then_var - if then_unreachable - if_var.bind_to conditional_no_return(node.then, then_var) - else - if_var.bind_to then_var - end + if then_var && else_var + if then_unreachable + if_var.bind_to conditional_no_return(node.then, then_var) + else + if_var.bind_to then_var + end - if cond_var - if_var.bind_to cond_var - elsif !else_unreachable - if_var.bind_to program.nil_var - if_var.nil_if_read = true - else - if_var.bind_to conditional_no_return(node.else, @program.nil_var) - end - elsif else_var - if else_unreachable - if_var.bind_to conditional_no_return(node.else, else_var) - else - if_var.bind_to else_var - end + if else_unreachable + if_var.bind_to conditional_no_return(node.else, else_var) + else + if_var.bind_to else_var + end + elsif then_var + if then_unreachable + if_var.bind_to conditional_no_return(node.then, then_var) + else + if_var.bind_to then_var + end - if cond_var - if_var.bind_to cond_var - elsif !then_unreachable - if_var.bind_to program.nil_var - if_var.nil_if_read = true - else - if_var.bind_to conditional_no_return(node.then, @program.nil_var) - end + if cond_var + if_var.bind_to cond_var + elsif !else_unreachable + if_var.bind_to program.nil_var + if_var.nil_if_read = true + else + if_var.bind_to conditional_no_return(node.else, @program.nil_var) + end + elsif else_var + if else_unreachable + if_var.bind_to conditional_no_return(node.else, else_var) + else + if_var.bind_to else_var end - @vars[name] = if_var + if cond_var + if_var.bind_to cond_var + elsif !then_unreachable + if_var.bind_to program.nil_var + if_var.nil_if_read = true + else + if_var.bind_to conditional_no_return(node.then, @program.nil_var) + end end + + @vars[name] = if_var end def conditional_no_return(node, var)