Skip to content

Instantly share code, notes, and snippets.

@baroquebobcat
Created August 12, 2012 19:46
Show Gist options
  • Select an option

  • Save baroquebobcat/3334047 to your computer and use it in GitHub Desktop.

Select an option

Save baroquebobcat/3334047 to your computer and use it in GitHub Desktop.
Mirah Office Hours: August 12th 2012

Plans

  • varargs transform / code generation I've got code for matching varargs methods, but the calls to them blow up because the args aren't right.
  • fixing tests on 1.6.7
  • fixing tests on 1.7.0.preview2
  • issue triage. There's stuff that only applies to 0-0-stable, which isn't going to be used going forward.

other thoughts

  • could be neat, needs tests
  • I'm not sure if I would like all arrays to be primitive arrays by default hmm How does JRuby handle this? Maybe we could guess and make primitive arrays when the arrays were used primitively and Lists when they are not. That sounds like it could become nasty confusing though. Maybe have a different array literal for primitive arrays?

varargs

my test was bad, because it looked like this:

  puts String.format "%02d %s's", 2, "bananas"

Not a problem in itself, but the type inference engine doesn't do primitive to Object conversion all that well. So, it didn't work. :sadface:

diff --git a/Gemfile b/Gemfile
index 29f3d6a..192de8d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,7 +3,7 @@ source :rubygems
 gemspec
 
 gem "rake"
-gem "bitescript", :git => 'https://github.com/headius/bitescript.git'
+gem "bitescript", :path => '../bitescript' #:git => 'https://github.com/headius/bitescript.git'
 # To test against a local copy of bitescript,
 # replace ":git => ''" with ":path => '<path to your local copy>'"
 gem 'turn'
diff --git a/lib/mirah/jvm/method_lookup.rb b/lib/mirah/jvm/method_lookup.rb
index 02899ed..7000ec4 100644
--- a/lib/mirah/jvm/method_lookup.rb
+++ b/lib/mirah/jvm/method_lookup.rb
@@ -111,8 +111,9 @@ module Mirah
 
       def find_jls2(mapped_type, name, mapped_params, meta, by_name, include_fields=true)
         return nil if mapped_params.any? {|p| p.nil? || p.isError}
-        # filter by arity
-        by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
+
+        # filter by arity, varargs
+        by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size }
 
         phase1_methods = phase1(mapped_params, by_name_and_arity)
 
@@ -125,7 +126,7 @@ module Mirah
 
         phase1_methods[0] ||
           phase2(mapped_params, by_name) ||
-          phase3(mapped_params, by_name) ||
+          phase3(mapped_params, by_name)[0] ||
           (include_fields &&
             (field_lookup(mapped_params, mapped_type, meta, name) ||
              inner_class(mapped_params, mapped_type, meta, name)))
@@ -179,7 +180,39 @@ module Mirah
       end
 
       def phase3(mapped_params, potentials)
-        nil
+        puts "DEBUG: in phase3 #{mapped_params.join(", ")}" if potentials.any? {|p|p.name == "format" }
+        # varargs
+        potential_varargs = potentials.select{|m| m.varargs? }# &&
+#          m.argument_types.size <= mapped_params.size}
+        methods = potential_varargs.inject([]) do |currents, potential|
+          method_params = potential.argument_types
+
+          # match n-1 params of potential
+          non_varargs_params, possible_varargs_params = mapped_params.partition.with_index{|param,i| i < method_params.size-1}
+
+          vararg_types = possible_varargs_params.size.times.map{ method_params.last.component_type }
+
+          puts "DEBUG: in phase3 - currents(#{currents.size})"," total args (#{mapped_params.size}/#{method_params.size})",
+               "  non vararg types [#{method_params[0..-2].join ", "}",
+               "  vararg type #{vararg_types.first}",
+               "  exact non varargs(#{non_varargs_params.size}) #{each_is_exact(non_varargs_params, method_params[0..-2])}  varargs(#{possible_varargs_params.size})  #{each_is_exact(possible_varargs_params, vararg_types)}",
+               "  non-exact non varargs(#{non_varargs_params.size}) #{each_is_exact_or_subtype_or_convertible(non_varargs_params, method_params[0..-2])}  varargs(#{possible_varargs_params.size})  #{each_is_exact_or_subtype_or_convertible(possible_varargs_params, vararg_types)}",
+          "  non-vararg params #{non_varargs_params}",
+          "  vararg params #{possible_varargs_params}"  if potential.name == "format" 
+       
+          if each_is_exact(non_varargs_params, method_params[0..-2]) &&
+             each_is_exact(possible_varargs_params, vararg_types)
+            return [potential]
+          end
+          
+
+          if each_is_exact_or_subtype_or_convertible(non_varargs_params, method_params[0..-2]) &&
+             each_is_exact_or_subtype_or_convertible(possible_varargs_params, vararg_types)
+            currents << potential
+          end
+
+          currents
+        end
       end
 
       def field_lookup(mapped_params, mapped_type, meta, name)
diff --git a/lib/mirah/jvm/types/methods.rb b/lib/mirah/jvm/types/methods.rb
index 50ae5fb..a3f637a 100644
--- a/lib/mirah/jvm/types/methods.rb
+++ b/lib/mirah/jvm/types/methods.rb
@@ -176,6 +176,11 @@ module Mirah::JVM::Types
     def constructor?
       true
     end
+
+    def varargs?
+      @member.varargs?
+    end
+
   end
 
   class JavaMethod < JavaConstructor
diff --git a/test/jvm/jvm_compiler_test.rb b/test/jvm/jvm_compiler_test.rb
index 108c7d0..9a0e847 100644
--- a/test/jvm/jvm_compiler_test.rb
+++ b/test/jvm/jvm_compiler_test.rb
@@ -1469,6 +1469,15 @@ class JVMCompilerTest < Test::Unit::TestCase
     # It shouldn't get confused by the Thread(String) constructor.
   end
 
+  def test_varargs_method_lookup
+    cls, = compile(<<-EOF)
+      puts String.format "%s %s's", "rocking", "bananas"
+    EOF
+    assert_output "rocking bananas\n" do
+      cls.main nil
+    end
+  end
+
   def test_optional_args
     cls, = compile(<<-EOF)
       def foo(a:int, b:int = 1, c:int = 2)

with the above got there:

  7) Error:
test_varargs_method_lookup(JVMCompilerTest):
Mirah::InternalCompilerError: undefined method `primitive?' for nil:NilClass
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/types/methods.rb:38:in `convert_args'
    org/jruby/RubyArray.java:1615:in `each'
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/types/methods.rb:36:in `convert_args'
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/types/methods.rb:293:in `call'
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/compiler/jvm_bytecode.rb:433:in `visitCall'
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/compiler/base.rb:51:in `visit'
    /Users/nick/hacking/mirah_hacking/mirah/lib/mirah/jvm/types/methods.rb:37:in `convert_args'
    org/jruby/RubyArray.java:1615:in `each'
  module ArgumentConversion
    def convert_args(compiler, values, types=nil)
      # TODO boxing/unboxing
      # TODO varargs
      types ||= argument_types
      values.zip(types).each do |value, type|
        compiler.visit(value, true)
        if type.primitive? && type != compiler.inferred_type(value) # <=======
            compiler.inferred_type(value).compile_widen(compiler.method, type)
        end
      end
    end
  end

zip is cool until you don't quite have enough types.

skipping to fixing tests, varargs is hard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment