class Steep::TypeInference::LogicTypeInterpreter

def eval(env:, type:, node:)

def eval(env:, type:, node:)
  value_node, vars = decompose_value(node)
  truthy_env = env
  falsy_env = env
  if type.is_a?(AST::Types::Any)
    type = guess_type_from_method(node) || type
  end
  if type.is_a?(AST::Types::Logic::Base)
    vars.each do |var_name|
      var_type = truthy_env[var_name]
      truthy_type, falsy_type = factory.unwrap_optional(var_type)
      falsy_type ||= AST::Builtin.nil_type
      truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type) {|_, type, _| type }
      falsy_env = truthy_env.assign!(var_name, node: node, type: falsy_type) {|_, type, _| type }
    end
    case type
    when AST::Types::Logic::Env
      truthy_env = type.truthy
      falsy_env = type.falsy
    when AST::Types::Logic::ReceiverIsNil
      case value_node.type
      when :send
        receiver = value_node.children[0]
        if receiver
          _, receiver_vars = decompose_value(receiver)
          receiver_vars.each do |receiver_var|
            var_type = env[receiver_var]
            truthy_type, falsy_type = factory.unwrap_optional(var_type)
            truthy_env = truthy_env.assign!(receiver_var, node: node, type: falsy_type || AST::Builtin.nil_type)
            falsy_env = falsy_env.assign!(receiver_var, node: node, type: truthy_type)
          end
        end
      end
    when AST::Types::Logic::ReceiverIsArg
      case value_node.type
      when :send
        receiver, _, arg = value_node.children
        if receiver
          _, receiver_vars = decompose_value(receiver)
          arg_type = typing.type_of(node: arg)
          if arg_type.is_a?(AST::Types::Name::Singleton)
            receiver_vars.each do |var_name|
              case var_name
              when :_, :__any__, :__skip__
                # skip
              else
                var_type = env[var_name]
                truthy_type, falsy_type = type_case_select(var_type, arg_type.name)
                truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
                falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
              end
            end
          end
        end
      end
    when AST::Types::Logic::ArgIsReceiver
      case value_node.type
      when :send
        receiver, _, arg = value_node.children
        if receiver
          _, arg_vars = decompose_value(arg)
          receiver_type = factory.deep_expand_alias(typing.type_of(node: receiver))
          if receiver_type.is_a?(AST::Types::Name::Singleton)
            arg_vars.each do |var_name|
              var_type = env[var_name]
              truthy_type, falsy_type = type_case_select(var_type, receiver_type.name)
              truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
              falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
            end
          end
        end
      end
    when AST::Types::Logic::ArgEqualsReceiver
      case value_node.type
      when :send
        receiver, _, arg = value_node.children
        if receiver
          _, arg_vars = decompose_value(arg)
          arg_vars.each do |var_name|
            var_type = factory.deep_expand_alias(env[var_name])
            truthy_types, falsy_types = literal_var_type_case_select(receiver, var_type)
            truthy_env = truthy_env.assign!(var_name, node: node, type: AST::Types::Union.build(types: truthy_types, location: nil))
            falsy_env = falsy_env.assign!(var_name, node: node, type: AST::Types::Union.build(types: falsy_types, location: nil))
          end
        end
      end
    when AST::Types::Logic::Not
      receiver, * = value_node.children
      receiver_type = typing.type_of(node: receiver)
      falsy_env, truthy_env = eval(env: env, type: receiver_type, node: receiver)
    end
  else
    _, vars = decompose_value(node)
    vars.each do |var_name|
      var_type = env[var_name]
      truthy_type, falsy_type = factory.unwrap_optional(var_type)
      if falsy_type
        truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
        falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
      else
        truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
        falsy_env = falsy_env.assign!(var_name, node: node, type: truthy_type)
      end
    end
  end
  [truthy_env, falsy_env]
end