diff --git a/lib/mirah/ast/structure.rb b/lib/mirah/ast/structure.rb index 775cd4ab..356c10d9 100644 --- a/lib/mirah/ast/structure.rb +++ b/lib/mirah/ast/structure.rb @@ -143,7 +143,7 @@ def initialize(parent, position, &block) def prepare(typer, method) mirah = typer.transformer - interface = method.argument_types[-1] + interface_or_abstract_class = method.argument_types[-1] outer_class = scope.defining_class binding = scope.binding_type(mirah) @@ -151,7 +151,15 @@ def prepare(typer, method) name = "#{outer_class.name}$#{mirah.tmp}" klass = mirah.define_closure(position, name, outer_class) - klass.interfaces = [interface] + case + when interface_or_abstract_class.interface? + klass.interfaces = [interface_or_abstract_class] + when interface_or_abstract_class.abstract? + klass.superclass = interface_or_abstract_class + else + raise "#{interface_or_abstract_class.name} isn't an interface or abstract" + end + klass.define_constructor(position, ['binding', binding]) do |c| mirah.eval("@binding = binding", '-', c, 'binding') @@ -205,7 +213,7 @@ def add_methods(klass, binding, typer) def build_method(klass, binding, typer) # find all methods which would not otherwise be on java.lang.Object - impl_methods = find_methods(klass.interfaces).select do |m| + impl_methods = find_abstract_methods(klass).select do |m| begin # Very cumbersome. Not sure how it got this way. mirror = BiteScript::ASM::ClassMirror.for_name('java.lang.Object') @@ -241,14 +249,18 @@ def build_method(klass, binding, typer) end end - def find_methods(interfaces) + def find_abstract_methods(klass) methods = [] - interfaces = interfaces.dup + interfaces = klass.interfaces.dup until interfaces.empty? interface = interfaces.pop methods += interface.declared_instance_methods.select {|m| m.abstract?} interfaces.concat(interface.interfaces) end + + if klass.superclass && klass.superclass.abstract? + methods += klass.superclass.declared_instance_methods.select{|m| m.abstract? } + end methods end end diff --git a/lib/mirah/jvm/method_lookup.rb b/lib/mirah/jvm/method_lookup.rb index 7569dfa3..3032a6ed 100644 --- a/lib/mirah/jvm/method_lookup.rb +++ b/lib/mirah/jvm/method_lookup.rb @@ -21,6 +21,7 @@ def log(msg); end def find_method(mapped_type, name, mapped_params, meta) raise ArgumentError if mapped_params.any? {|p| p.nil?} + if name == 'new' if meta name = "" diff --git a/lib/mirah/jvm/types/type.rb b/lib/mirah/jvm/types/type.rb index 30da87d2..5cca8e68 100644 --- a/lib/mirah/jvm/types/type.rb +++ b/lib/mirah/jvm/types/type.rb @@ -52,6 +52,10 @@ def interface? # mirrors for all incoming types without blowing up on e.g. 'boolean' or 'int' (@type || BiteScript::ASM::ClassMirror.for_name(@name)).interface? rescue nil end + + def abstract? + (@type || BiteScript::ASM::ClassMirror.for_name(@name)).abstract? rescue nil + end def dynamic? false @@ -76,7 +80,7 @@ def assignable_from?(other) return true if other.error? || other.unreachable? # TODO should we allow more here? - return interface? if other.block? + return interface? || abstract? if other.block? return true if jvm_type && (jvm_type == other.jvm_type) @@ -170,4 +174,4 @@ def aload(builder) end end end -end \ No newline at end of file +end diff --git a/lib/mirah/transform/helper.rb b/lib/mirah/transform/helper.rb index cdd63df5..6ec21910 100644 --- a/lib/mirah/transform/helper.rb +++ b/lib/mirah/transform/helper.rb @@ -762,4 +762,4 @@ def transform_annotation(node, parent) end end end -end \ No newline at end of file +end diff --git a/test/jvm/blocks_test.rb b/test/jvm/blocks_test.rb index 1a3aae9d..d14f0807 100644 --- a/test/jvm/blocks_test.rb +++ b/test/jvm/blocks_test.rb @@ -24,7 +24,7 @@ def setup def parse_and_type code, name=tmp_script_name parse_and_resolve_types name, code end - + #this should probably be a core test def test_empty_block_parses_and_types_without_error assert_nothing_raised do @@ -259,4 +259,20 @@ def foo(a:Bar) end CODE end + + def test_method_requiring_subclass_of_abstract_class_finds_abstract_method + cls, = compile(<<-EOF) + import java.io.OutputStream + def foo x:OutputStream + x.write byte(1) + rescue + end + foo do |b:int| + puts "writing" + end + EOF + assert_output "writing\n" do + cls.main(nil) + end + end end