- 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?
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
endzip is cool until you don't quite have enough types.