Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

fix #186 improving abstract class based closure support

  • Loading branch information...
commit 5b1c8b117177fd48e3ef9a8124ccc624480811bf 1 parent 40a0c94
@baroquebobcat baroquebobcat authored
View
22 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
View
1  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 = "<init>"
View
8 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
+end
View
2  lib/mirah/transform/helper.rb
@@ -762,4 +762,4 @@ def transform_annotation(node, parent)
end
end
end
-end
+end
View
18 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
Please sign in to comment.
Something went wrong with that request. Please try again.