<commit_before>module Duby::AST
  class Body < Node
    def initialize(parent, line_number, &block)
      super(parent, line_number, &block)
    end

    # Type of a block is the type of its final element
    def infer(typer)
      unless @inferred_type
        if children.size == 0
          @inferred_type = typer.default_type
        else
          children.each {|child| @inferred_type = typer.infer(child)}
        end

        if @inferred_type
          resolved!
        else
          typer.defer(self)
        end
      end

      @inferred_type
    end
  end

  class Block < Node
    include Scoped
    child :args
    child :body

    def initialize(parent, position, &block)
      super(parent, position, &block)
    end

    def prepare(typer, method)
      duby = typer.transformer
      interface = method.argument_types[-1]
      outer_class = scope.defining_class
      name = "#{outer_class.name}$#{duby.tmp}"
      klass = duby.define_class(position, name)
      klass.interfaces = [interface]
      klass.define_constructor(position)
      find_methods(interface).each do |method|
        klass.define_method(position,
                            method.name,
                            method.actual_return_type,
                            args.dup).body = body.dup
      end
      call = parent
      instance = Call.new(call, position, 'new')
      instance.target = Constant.new(call, position, name)
      instance.parameters = []
      call.parameters << instance
      typer.infer(klass)
      typer.infer(instance)
    end

    def find_methods(interface)
      methods = []
      interfaces = [interface]
      until interfaces.empty?
        interface = interfaces.pop
        methods += interface.declared_instance_methods.select {|m| m.abstract?}
        interfaces.concat(interface.interfaces)
      end
      methods
    end
  end

  class Noop < Node
    def infer(typer)
      resolved!
      @inferred_type ||= typer.no_type
    end
  end

  class Script < Node
    include Scope
    child :body

    def initialize(parent, line_number, &block)
      super(parent, line_number, children, &block)
    end

    def infer(typer)
      @inferred_type ||= typer.infer(body) || (typer.defer(self); nil)
    end
  end
end<commit_msg>Add an error when trying to impl multiple abstract methods with a closure.<commit_after>module Duby::AST
  class Body < Node
    def initialize(parent, line_number, &block)
      super(parent, line_number, &block)
    end

    # Type of a block is the type of its final element
    def infer(typer)
      unless @inferred_type
        if children.size == 0
          @inferred_type = typer.default_type
        else
          children.each {|child| @inferred_type = typer.infer(child)}
        end

        if @inferred_type
          resolved!
        else
          typer.defer(self)
        end
      end

      @inferred_type
    end
  end

  class Block < Node
    include Scoped
    child :args
    child :body

    def initialize(parent, position, &block)
      super(parent, position, &block)
    end

    def prepare(typer, method)
      duby = typer.transformer
      interface = method.argument_types[-1]
      outer_class = scope.defining_class
      name = "#{outer_class.name}$#{duby.tmp}"
      klass = duby.define_class(position, name)
      klass.interfaces = [interface]
      klass.define_constructor(position)
      impl_methods = find_methods(interface)
      # TODO: find a nice way to closure-impl multiple methods
      # perhaps something like
      # Collections.sort(list) do
      #   def equals(other); self == other; end
      #   def compareTo(x,y); Comparable(x).compareTo(y); end
      # end
      raise "Multiple abstract methods found; cannot use block" if impl_methods.size > 1
      impl_methods.each do |method|
        klass.define_method(position,
                            method.name,
                            method.actual_return_type,
                            args.dup).body = body.dup
      end
      call = parent
      instance = Call.new(call, position, 'new')
      instance.target = Constant.new(call, position, name)
      instance.parameters = []
      call.parameters << instance
      typer.infer(klass)
      typer.infer(instance)
    end

    def find_methods(interface)
      methods = []
      interfaces = [interface]
      until interfaces.empty?
        interface = interfaces.pop
        methods += interface.declared_instance_methods.select {|m| m.abstract?}
        interfaces.concat(interface.interfaces)
      end
      methods
    end
  end

  class Noop < Node
    def infer(typer)
      resolved!
      @inferred_type ||= typer.no_type
    end
  end

  class Script < Node
    include Scope
    child :body

    def initialize(parent, line_number, &block)
      super(parent, line_number, children, &block)
    end

    def infer(typer)
      @inferred_type ||= typer.infer(body) || (typer.defer(self); nil)
    end
  end
end
{'fraction_non_alphanumeric': 0.0881287726358149, 'fraction_numerical': 0.001006036217303823, 'mean_word_length': 2.170280612244898, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7428552', 'n_tokens_mistral': 1469, 'n_tokens_neox': 1445, 'n_words': 371}