mirah 0.1.0.pre-java → 0.1.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. data/History.txt +736 -0
  2. data/README.md +71 -0
  3. data/Rakefile +227 -73
  4. data/examples/Fib.class +0 -0
  5. data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +2 -3
  6. data/examples/simple_class.mirah +3 -3
  7. data/examples/{dynamic.mirah → simple_class.mirah~} +7 -12
  8. data/javalib/mirah-bootstrap.jar +0 -0
  9. data/javalib/mirah-builtins.jar +0 -0
  10. data/javalib/mirah-compiler.jar +0 -0
  11. data/javalib/mirah-parser.jar +0 -0
  12. data/javalib/mirah-util.jar +0 -0
  13. data/lib/mirah.rb +8 -1
  14. data/lib/mirah/ast.rb +1 -1
  15. data/lib/mirah/ast/scope.rb +16 -0
  16. data/lib/mirah/commands/base.rb +1 -3
  17. data/lib/mirah/compiler.rb +17 -3
  18. data/lib/mirah/errors.rb +10 -10
  19. data/lib/mirah/generator.rb +21 -9
  20. data/lib/mirah/jvm/compiler.rb +17 -0
  21. data/lib/mirah/jvm/compiler/base.rb +24 -5
  22. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +83 -20
  23. data/lib/mirah/jvm/method_lookup.rb +43 -22
  24. data/lib/mirah/jvm/types.rb +1 -2
  25. data/lib/mirah/jvm/types/array_type.rb +1 -6
  26. data/lib/mirah/jvm/types/ast_ext.rb +31 -0
  27. data/lib/mirah/jvm/types/basic_types.rb +1 -2
  28. data/lib/mirah/jvm/types/boolean.rb +11 -10
  29. data/lib/mirah/jvm/types/extensions.rb +14 -5
  30. data/lib/mirah/jvm/types/factory.rb +128 -43
  31. data/lib/mirah/jvm/types/floats.rb +8 -10
  32. data/lib/mirah/jvm/types/integers.rb +16 -9
  33. data/lib/mirah/jvm/types/intrinsics.rb +17 -69
  34. data/lib/mirah/jvm/types/meta_type.rb +5 -0
  35. data/lib/mirah/jvm/types/methods.rb +317 -151
  36. data/lib/mirah/jvm/types/methods.rb~ +973 -0
  37. data/lib/mirah/jvm/types/number.rb +29 -6
  38. data/lib/mirah/jvm/types/primitive_type.rb +35 -7
  39. data/lib/mirah/jvm/types/source_mirror.rb +11 -6
  40. data/lib/mirah/jvm/types/type.rb +52 -0
  41. data/lib/mirah/jvm/types/type_definition.rb +8 -2
  42. data/lib/mirah/transform/ast_ext.rb +9 -31
  43. data/lib/mirah/transform/transformer.rb +1 -1
  44. data/lib/mirah/typer.rb +2 -1
  45. data/lib/mirah/util/argument_processor.rb +10 -14
  46. data/lib/mirah/util/argument_processor.rb~ +146 -0
  47. data/lib/mirah/util/compilation_state.rb +15 -9
  48. data/lib/mirah/util/process_errors.rb +8 -2
  49. data/lib/mirah/version.rb +2 -2
  50. data/lib/mirah_task.rb +0 -7
  51. data/test/core/typer_test.rb +21 -13
  52. data/test/core/util/argument_processor_test.rb +19 -19
  53. data/test/core/util/class_loader_test.rb +19 -4
  54. data/test/core/util/compilation_state_test.rb +38 -0
  55. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  56. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  57. data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
  58. data/test/jvm/blocks_test.rb +50 -29
  59. data/test/jvm/bytecode_test_helper.rb +71 -57
  60. data/test/jvm/cast_test.rb +162 -0
  61. data/test/jvm/constructors_test.rb +48 -0
  62. data/test/jvm/enumerable_test.rb +136 -7
  63. data/test/jvm/example_test.rb +39 -0
  64. data/test/jvm/factory_test.rb +6 -0
  65. data/test/jvm/generics_test.rb +0 -5
  66. data/test/jvm/import_test.rb +81 -0
  67. data/test/jvm/interface_test.rb +113 -0
  68. data/test/jvm/java_typer_test.rb +57 -11
  69. data/test/jvm/jvm_commands_test.rb +24 -0
  70. data/test/jvm/jvm_compiler_test.rb +186 -370
  71. data/test/jvm/macros_test.rb +67 -6
  72. data/test/jvm/main_method_test.rb +1 -1
  73. data/test/jvm/mirror_compilation_test_helper.rb +24 -0
  74. data/test/jvm/new_backend_test_helper.rb +25 -0
  75. data/test/jvm/rescue_test.rb +153 -18
  76. data/test/jvm/string_test.rb +41 -0
  77. data/test/jvm/varargs_test.rb +65 -0
  78. data/test/mirrors/base_type_test.rb +96 -0
  79. data/test/mirrors/bytecode_mirror_test.rb +86 -0
  80. data/test/mirrors/generics_test.rb +776 -0
  81. data/test/mirrors/member_test.rb +69 -0
  82. data/test/mirrors/method_lookup_test.rb +574 -0
  83. data/test/mirrors/mirrors_test.rb +562 -0
  84. data/test/mirrors/simple_async_mirror_loader_test.rb +110 -0
  85. data/test/mirrors/simple_mirror_loader_test.rb +104 -0
  86. data/test/test_helper.rb +2 -1
  87. metadata +244 -217
  88. data/README.txt +0 -59
  89. data/javalib/dynalink-0.2.jar +0 -0
  90. data/lib/mirah/jvm/typer.rb +0 -177
  91. data/lib/mirah/jvm/types/dynamic_type.rb +0 -45
  92. data/lib/mirah/jvm/types/unreachable_type.rb +0 -27
@@ -0,0 +1,69 @@
1
+ # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
2
+ # All contributing project authors may be found in the NOTICE file.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'test/unit'
17
+ require 'mirah'
18
+
19
+ class MembersTest < Test::Unit::TestCase
20
+ java_import 'org.mirah.jvm.mirrors.Member'
21
+ java_import 'org.mirah.jvm.types.JVMType'
22
+ java_import 'org.mirah.jvm.types.MemberKind'
23
+
24
+ class Visitor
25
+ def method_missing(name, *args)
26
+ @visited = name
27
+ end
28
+ attr_reader :visited
29
+ end
30
+
31
+ class FakeType
32
+ include JVMType
33
+ end
34
+
35
+ def create_member(kind)
36
+ @flags = kind.name.hash
37
+ @name = "foo#{kind}"
38
+ @klass = FakeType.new
39
+ @args = [FakeType.new]
40
+ @return_type = FakeType.new
41
+ Member.new(@flags, @klass, @name, @args, @return_type, kind)
42
+ end
43
+
44
+ def check_fields(member, kind)
45
+ assert_equal(@flags, member.flags)
46
+ assert_equal(@name, member.name)
47
+ assert_equal(@klass, member.declaringClass)
48
+ assert_equal(@args, member.argumentTypes.to_a)
49
+ assert_equal(@return_type, member.returnType)
50
+ assert_equal(kind, member.kind)
51
+ end
52
+
53
+ def check_visitor(member, kind)
54
+ visitor = Visitor.new
55
+ member.accept(visitor, false)
56
+ assert_match(/^#{visitor.visited}/i, "visit#{kind.name.gsub('_','')}call")
57
+ end
58
+
59
+ MemberKind.constants.each do |name|
60
+ eval(<<-EOF)
61
+ def test_#{name}
62
+ kind = MemberKind.const_get(:#{name})
63
+ member = create_member(kind)
64
+ check_fields(member, kind)
65
+ check_visitor(member, kind)
66
+ end
67
+ EOF
68
+ end
69
+ end
@@ -0,0 +1,574 @@
1
+ # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
2
+ # All contributing project authors may be found in the NOTICE file.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'test/unit'
17
+ require 'mirah'
18
+
19
+ class BaseMethodLookupTest < Test::Unit::TestCase
20
+ java_import 'org.mirah.jvm.mirrors.MirrorTypeSystem'
21
+ java_import 'org.mirah.jvm.mirrors.JVMScope'
22
+ java_import 'org.mirah.jvm.mirrors.BaseType'
23
+ java_import 'org.mirah.jvm.mirrors.MethodLookup'
24
+ java_import 'org.mirah.jvm.mirrors.LookupState'
25
+ java_import 'org.mirah.jvm.mirrors.FakeMember'
26
+ java_import 'org.mirah.jvm.mirrors.Member'
27
+ java_import 'org.mirah.jvm.mirrors.MetaType'
28
+ java_import 'org.mirah.jvm.types.MemberKind'
29
+ java_import 'org.mirah.typer.BaseTypeFuture'
30
+ java_import 'org.mirah.typer.ErrorType'
31
+ java_import 'org.jruby.org.objectweb.asm.Opcodes'
32
+ java_import 'org.jruby.org.objectweb.asm.Type'
33
+
34
+ class FakeMirror < BaseType
35
+ def initialize(desc, superclass=nil, flags=Opcodes.ACC_PUBLIC)
36
+ super(nil, Type.getType(desc), flags, superclass)
37
+ @fields = {}
38
+ end
39
+
40
+ def add_field(name, flags=Opcodes.ACC_PUBLIC)
41
+
42
+ kind = if (flags & Opcodes.ACC_STATIC) == 0
43
+ MemberKind::FIELD_ACCESS
44
+ else
45
+ MemberKind::STATIC_FIELD_ACCESS
46
+ end
47
+ @fields[name] = Member.new(flags, self, name, [], self, kind)
48
+ end
49
+
50
+ def getDeclaredField(name)
51
+ @fields[name]
52
+ end
53
+ end
54
+
55
+ def setup
56
+ @types = MirrorTypeSystem.new
57
+ @scope = JVMScope.new
58
+ @lookup = MethodLookup.new(@types.context)
59
+ end
60
+
61
+ def jvmtype(internal_name, flags=0, superclass=nil)
62
+ BaseType.new(@types.context, Type.getObjectType(internal_name), flags, superclass || wrap('Ljava/lang/Object;'))
63
+ end
64
+
65
+ def wrap(descriptor)
66
+ wrap_type(Type.getType(descriptor))
67
+ end
68
+
69
+ def wrap_type(type)
70
+ @types.wrap(type).resolve
71
+ end
72
+
73
+ def make_method(tag, flags=-1)
74
+ FakeMember.create(@types, tag, flags)
75
+ end
76
+ end
77
+
78
+ class MethodLookupTest < BaseMethodLookupTest
79
+ def test_object_supertype
80
+ main_future = @types.getMainType(nil, nil)
81
+ object = @types.getSuperClass(main_future).resolve
82
+ main = main_future.resolve
83
+ assert(MethodLookup.isSubType(main, main))
84
+ assert(MethodLookup.isSubType(main, object))
85
+ assert_false(MethodLookup.isSubType(object, main))
86
+ error = ErrorType.new([['Error']])
87
+ assert(MethodLookup.isSubType(error, main))
88
+ assert(MethodLookup.isSubType(main, error))
89
+ end
90
+
91
+ # TODO interfaces
92
+ def check_supertypes(type, *supertypes)
93
+ supertypes.each do |supertype|
94
+ assert_block("Expected #{type} < #{supertype}") do
95
+ MethodLookup.isSubType(type, supertype)
96
+ end
97
+ assert_block("Expected #{type}.assignableFrom(#{supertype})") do
98
+ supertype.assignableFrom(type)
99
+ end
100
+ end
101
+ end
102
+
103
+ def check_not_supertypes(type, *supertypes)
104
+ supertypes.each do |supertype|
105
+ assert_block("Expected !(#{type} < #{supertype})") do
106
+ !MethodLookup.isSubType(type, supertype)
107
+ end
108
+ assert_block("Expected #{type}.assignableFrom(#{supertype}) = false") do
109
+ !supertype.assignableFrom(type)
110
+ end
111
+ end
112
+ end
113
+
114
+ def test_primitive_supertypes
115
+ double = wrap('D')
116
+ float = wrap('F')
117
+ long = wrap('J')
118
+ int = wrap('I')
119
+ short = wrap('S')
120
+ char = wrap('C')
121
+ byte = wrap('B')
122
+ bool = wrap('Z')
123
+ check_supertypes(double, double)
124
+ check_not_supertypes(double, float, long, int, short, char, byte, bool)
125
+ check_supertypes(float, double, float)
126
+ check_not_supertypes(float, long, int, short, char, byte, bool)
127
+ check_supertypes(long, double, float, long)
128
+ check_not_supertypes(long, int, short, char, byte, bool)
129
+ check_supertypes(int, double, float, long, int)
130
+ check_not_supertypes(int, short, char, byte, bool)
131
+ check_supertypes(short, double, float, long, int, short)
132
+ check_not_supertypes(short, char, byte, bool)
133
+ check_supertypes(char, double, float, long, int, char)
134
+ check_not_supertypes(char, byte, bool)
135
+ check_supertypes(byte, double, float, long, int, short)
136
+ check_not_supertypes(byte, char, bool)
137
+ check_supertypes(bool, bool)
138
+ check_not_supertypes(bool, double, float, long, int, short, char, byte)
139
+ end
140
+
141
+ def array(desc)
142
+ @types.getArrayType(wrap(desc))
143
+ end
144
+
145
+ def test_array_supertypes
146
+ check_supertypes(array("I"),
147
+ array("I"),
148
+ wrap("Ljava/lang/Object;"),
149
+ wrap("Ljava/lang/Cloneable;"),
150
+ wrap("Ljava/io/Serializable;"))
151
+ check_not_supertypes(array("I"), array("J"), array("S"), array("D"),
152
+ array("Ljava/lang/Object;"))
153
+ check_supertypes(array("Ljava/util/Map;"),
154
+ wrap("Ljava/lang/Object;"),
155
+ wrap("Ljava/lang/Cloneable;"),
156
+ wrap("Ljava/io/Serializable;"),
157
+ array("Ljava/lang/Object;"),
158
+ array("Ljava/util/Map;"))
159
+ check_supertypes(array("Ljava/util/HashMap;"),
160
+ wrap("Ljava/lang/Object;"),
161
+ wrap("Ljava/lang/Cloneable;"),
162
+ wrap("Ljava/io/Serializable;"),
163
+ array("Ljava/lang/Object;"),
164
+ array("Ljava/util/Map;"),
165
+ array("Ljava/io/Serializable;"),
166
+ array("Ljava/util/AbstractMap;"))
167
+ end
168
+
169
+ def test_subtype_comparison
170
+ double = wrap('D')
171
+ int = wrap('I')
172
+ short = wrap('S')
173
+ assert_equal(0.0, MethodLookup.subtypeComparison(double, double))
174
+ assert_equal(0.0, MethodLookup.subtypeComparison(int, int))
175
+ assert_equal(1.0, MethodLookup.subtypeComparison(int, double))
176
+ assert_equal(-1.0, MethodLookup.subtypeComparison(double, int))
177
+ assert_equal(-1.0, MethodLookup.subtypeComparison(int, short))
178
+ assert_equal(1.0, MethodLookup.subtypeComparison(short, int))
179
+
180
+ main = @types.getMainType(nil, nil).resolve
181
+ assert_equal(0.0, MethodLookup.subtypeComparison(main, main))
182
+ assert(MethodLookup.subtypeComparison(double, main).nan?)
183
+ assert(MethodLookup.subtypeComparison(main, int).nan?)
184
+ end
185
+
186
+ def test_boxing
187
+ a = @types.getBooleanType.resolve
188
+ b = @types.wrap(Type.getType('Ljava/lang/Boolean;')).resolve
189
+ c = @types.getFixnumType(1).resolve
190
+ assert(!MethodLookup.isSubType(a, b))
191
+ assert(!MethodLookup.isSubType(b, a))
192
+ assert(MethodLookup.isSubTypeWithConversion(a, b))
193
+ assert(MethodLookup.isSubTypeWithConversion(b, a))
194
+ assert(!MethodLookup.isSubTypeWithConversion(c, b))
195
+ assert(!MethodLookup.isSubTypeWithConversion(b, c))
196
+ end
197
+
198
+ def test_pickMostSpecific
199
+ m = MethodLookup.pickMostSpecific([make_method('@I.()V'), make_method('@Z.()V')])
200
+ # Both ambiguous, one should be picked but it doesn't matter which
201
+ assert_kind_of(FakeMember, m)
202
+
203
+ expected = make_method('Z.()V')
204
+ methods = [expected, make_method('@I.()V'), make_method('@S.()V')].shuffle
205
+ assert_same(expected, MethodLookup.pickMostSpecific(methods))
206
+ end
207
+
208
+ def test_getPackage
209
+ assert_equal("", MethodLookup.getPackage(jvmtype('Foo')))
210
+ assert_equal("java/lang", MethodLookup.getPackage(wrap('Ljava/lang/String;')))
211
+ assert_equal("java/util", MethodLookup.getPackage(wrap('Ljava/util/Map$Entry;')))
212
+ end
213
+
214
+ def visibility_string(flags)
215
+ if 0 != (flags & Opcodes.ACC_PUBLIC)
216
+ return :public
217
+ elsif 0 != (flags & Opcodes.ACC_PROTECTED)
218
+ return :protected
219
+ elsif 0 != (flags & Opcodes.ACC_PRIVATE)
220
+ return :private
221
+ else
222
+ return :'package private'
223
+ end
224
+ end
225
+
226
+ def assert_visible(type, flags, visible, invisible=[], target=nil)
227
+ visible.each do |t|
228
+ accessibility_assertion(type, flags, t, true, target)
229
+ end
230
+ invisible.each do |t|
231
+ accessibility_assertion(type, flags, t, false, target)
232
+ end
233
+ end
234
+
235
+ def set_self_type(type)
236
+ future = BaseTypeFuture.new
237
+ future.resolved(type)
238
+ @scope.selfType_set(future)
239
+ end
240
+
241
+ def accessibility_assertion(a, flags, b, expected, target=nil)
242
+ assert_block "Expected #{visibility_string(flags)} #{a} #{expected ? '' : ' not '} visible from #{b}" do
243
+ set_self_type(b)
244
+ actual = MethodLookup.isAccessible(a, flags, @scope, target)
245
+ actual == expected
246
+ end
247
+ end
248
+
249
+ def test_isAccessible
250
+ object = wrap('Ljava/lang/Object;')
251
+ string = wrap('Ljava/lang/String;')
252
+ foo = jvmtype('Foo')
253
+ assert_visible(object, Opcodes.ACC_PUBLIC, [object, string, foo])
254
+ assert_visible(object, Opcodes.ACC_PROTECTED, [object, string, foo])
255
+ assert_visible(object, Opcodes.ACC_PRIVATE, [object], [string, foo])
256
+ assert_visible(object, 0, [object, string], [foo])
257
+ assert_visible(foo, Opcodes.ACC_PRIVATE, [foo], [object, string])
258
+ assert_visible(foo, Opcodes.ACC_PROTECTED, [foo], [object, string])
259
+ assert_visible(string, Opcodes.ACC_PROTECTED, [string, object], [foo]) # visible to same package
260
+ assert_visible(string, 0, [string, object], [foo])
261
+
262
+ # instance method from static scope
263
+ assert_visible(object, Opcodes.ACC_PUBLIC, [], [object, foo],
264
+ MetaType.new(object))
265
+ end
266
+
267
+ def assert_methods_visible(methods, type, expected_visible)
268
+ methods_desc = methods.inspect
269
+ expected_invisible = methods - expected_visible
270
+ set_self_type(type)
271
+ invisible = @lookup.removeInaccessible(methods, @scope, nil)
272
+ assert_equal(expected_invisible.map {|m| m.toString}, invisible.map {|m| m.toString})
273
+ assert_equal(expected_visible.map {|m| m.toString}, methods.map {|m| m.toString})
274
+ # TODO: fix protected usage. e.g. Foo can call Object.clone() through a foo instance, but not any Object.
275
+ end
276
+
277
+ def test_removeInaccessible
278
+ # test method from an inaccessible class
279
+ methods = [make_method("Ljava/lang/AbstractStringBuilder;.(I)V"), make_method("Ljava/lang/StringBuilder;.(I)V")]
280
+ assert_methods_visible(methods, wrap('Ljava/util/Map;'), [methods[1]])
281
+
282
+ # test inaccessible method
283
+ methods = [make_method("Ljava/lang/Object;.()V", Opcodes.ACC_PRIVATE), make_method("Ljava/lang/String;.()V")]
284
+ assert_methods_visible(methods, wrap('Ljava/util/Map;'), [methods[1]])
285
+ end
286
+
287
+ def test_gatherMethods
288
+ methods = @lookup.gatherMethods(wrap('Ljava/lang/String;'), 'toString')
289
+ assert_equal(3, methods.size)
290
+
291
+ declaring_classes = Set.new(methods.map {|m| m.declaringClass})
292
+ assert_equal(Set.new([wrap('Ljava/lang/Object;'),
293
+ wrap('Ljava/lang/String;'),
294
+ wrap('Ljava/lang/CharSequence;')]),
295
+ declaring_classes)
296
+ end
297
+
298
+ def test_method_splitting
299
+ set_self_type(jvmtype('Foo'))
300
+ methods = [make_method("Ljava/lang/Object;.()V", Opcodes.ACC_PRIVATE), make_method("Ljava/lang/String;.()V")]
301
+ state = LookupState.new(@types.context, @scope, wrap('Ljava/lang/String;'), methods, nil)
302
+ assert_equal("{potentials: 1 0 inaccessible: 1 0}", state.toString)
303
+ end
304
+
305
+ def test_search
306
+ set_self_type(jvmtype('Foo'))
307
+ methods = [make_method("Ljava/lang/Object;.()V")]
308
+ state = LookupState.new(@types.context, @scope, wrap('Ljava/lang/String;'), methods, nil)
309
+ state.search([], nil)
310
+ assert_equal("{1 methods 0 macros 0 inaccessible}", state.toString)
311
+ future = state.future(false)
312
+ assert_not_nil(future)
313
+ type = future.resolve
314
+ assert(!type.isError)
315
+ assert_equal("Ljava/lang/String;", type.returnType.asm_type.descriptor)
316
+ end
317
+
318
+ def test_findMethod
319
+ set_self_type(jvmtype('Foo'))
320
+ type = @lookup.findMethod(@scope, wrap('Ljava/lang/String;'), 'toString', [], nil, nil, false).resolve
321
+ assert(!type.isError, type.toString)
322
+ assert_nil(@lookup.findMethod(@scope, wrap('Ljava/lang/String;'), 'foobar', [], nil, nil, false))
323
+ type = @lookup.findMethod(@scope, wrap('Ljava/lang/Object;'), 'registerNatives', [], nil, nil, false).resolve
324
+ assert(type.isError)
325
+ assert_equal('Cannot access java.lang.Object.registerNatives() from Foo', type.message[0][0])
326
+ type = @lookup.findMethod(@scope, wrap('Ljava/lang/Object;'), 'clone', [], nil, nil, false).resolve
327
+ assert(type.isError)
328
+ assert_equal('Cannot access java.lang.Object.clone() from Foo', type.message[0][0])
329
+ # TODO test ambiguous
330
+ # TODO check calling instance method from static scope.
331
+ end
332
+ end
333
+
334
+ class CompareSpecificityTest < BaseMethodLookupTest
335
+ def test_same_method
336
+ m = 'I.(I)V'
337
+ assert_specificity_equal(m, m)
338
+ end
339
+
340
+ def assert_more_specific(a, b)
341
+ assert_specificity(a, b, 1.0)
342
+ assert_specificity(b, a, -1.0)
343
+ end
344
+
345
+ def assert_less_specific(a, b)
346
+ assert_more_specific(b, a)
347
+ end
348
+
349
+ def assert_specificity_equal(a, b)
350
+ assert_specificity(a, b, 0.0)
351
+ assert_specificity(b, a, 0.0)
352
+ end
353
+
354
+ def assert_ambiguous(a, b)
355
+ nan = 0.0 / 0.0
356
+ assert_specificity(a, b, nan)
357
+ assert_specificity(b, a, nan)
358
+ end
359
+
360
+ def assert_specificity(a, b, value)
361
+ actual = MethodLookup.compareSpecificity(make_method(a), make_method(b))
362
+ assert_block "Expected compareSpecificity(#{a.inspect}, #{b.inspect}) = #{value} but was #{actual}" do
363
+ if value.nan?
364
+ actual.nan?
365
+ else
366
+ actual == value
367
+ end
368
+ end
369
+ end
370
+
371
+ def test_target
372
+ a = 'I.()V'
373
+ b = 'S.()V'
374
+
375
+ assert_more_specific(b, a)
376
+ end
377
+
378
+ def test_target_with_same_args
379
+ a = 'I.(II)V'
380
+ b = 'S.(II)V'
381
+
382
+ assert_more_specific(b, a)
383
+ end
384
+
385
+ def test_ambiguous_target
386
+ # if the target is ambiguous the result should be equal
387
+ assert_specificity_equal('Z.()V', 'I.()V')
388
+ assert_specificity_equal('Z.(I)V', 'I.(I)V')
389
+ assert_specificity_equal('Z.(II)V', 'I.(II)V')
390
+
391
+ # unless the arguments are different
392
+ assert_ambiguous('Z.(S)V', 'I.(I)V')
393
+ assert_ambiguous('Z.(I)V', 'I.(S)V')
394
+ end
395
+
396
+ def test_arguments
397
+ assert_more_specific('I.(S)V', 'I.(I)V')
398
+ assert_more_specific('I.(SS)V', 'I.(II)V')
399
+ assert_more_specific('I.(SI)V', 'I.(II)V')
400
+ assert_more_specific('I.(IS)V', 'I.(II)V')
401
+ end
402
+
403
+ def test_ambiguous_arguments
404
+ assert_ambiguous('I.(S)V', 'I.(Z)V')
405
+ assert_ambiguous('I.(S)V', 'S.(Z)V')
406
+ assert_ambiguous('S.(S)V', 'I.(Z)V')
407
+ end
408
+
409
+ def test_return_type_ignored
410
+ a = 'I.()I'
411
+ b = 'I.()S'
412
+ c = 'C.()D'
413
+ assert_specificity_equal(a, b)
414
+ assert_more_specific(c, a)
415
+ assert_more_specific(c, b)
416
+ end
417
+ end
418
+
419
+ class FindMaximallySpecificTest < BaseMethodLookupTest
420
+ def find_maximally_specific(method_tags)
421
+ methods = {}
422
+ method_tags.each do |m|
423
+ method = make_method(m)
424
+ methods[method] = m
425
+ end
426
+ result = MethodLookup.findMaximallySpecific(methods.keys)
427
+ result.map {|m| methods[m] || m}
428
+ end
429
+
430
+ def assert_most_specific(expected, methods)
431
+ assert_maximal([expected], methods)
432
+ end
433
+
434
+ def assert_maximal(expected, methods)
435
+ actual = find_maximally_specific(methods)
436
+ assert_equal(Set.new(expected), Set.new(actual))
437
+ end
438
+
439
+ def test_single_method
440
+ m = 'I.()V'
441
+ assert_most_specific(m, [m])
442
+ end
443
+
444
+ def test_more_specific
445
+ a = 'I.(I)V'
446
+ b = 'I.(S)V'
447
+ assert_most_specific(b, [a, b])
448
+ end
449
+
450
+ def test_ambiguous
451
+ a = 'I.(II)V'
452
+ b = 'I.(SI)V'
453
+ c = 'I.(IS)V'
454
+ assert_maximal([b, c], [a, b, c])
455
+ end
456
+
457
+ def test_all_abstract
458
+ a = 'I.(II)V'
459
+ b = '@I.(SI)V'
460
+ c = '@Z.(SI)V'
461
+ result = find_maximally_specific([a, b, c])
462
+ # either b or c should be picked.
463
+ begin
464
+ assert_equal([b], result)
465
+ rescue
466
+ assert_equal([c], result)
467
+ end
468
+ end
469
+
470
+ def test_one_not_abstract
471
+ a = 'I.(SI)V'
472
+ b = '@I.(SI)V'
473
+ c = '@Z.(SI)V'
474
+ assert_most_specific(a, [a, b, c])
475
+ end
476
+ end
477
+
478
+ class Phase1Test < BaseMethodLookupTest
479
+ def phase1(methods, params)
480
+ methods = @lookup.phase1(methods.map{|m| make_method(m)}, params.map{|p| wrap(p)})
481
+ methods.map {|m| m.toString } if methods
482
+ end
483
+
484
+ def test_no_match
485
+ assert_nil(phase1([], ['I']))
486
+ end
487
+
488
+ def test_simpe_match
489
+ assert_equal(['I.()V'], phase1(['I.()V'], []))
490
+ assert_equal(['I.(I)V'], phase1(['I.(I)V'], ['I']))
491
+ end
492
+
493
+ def test_arity
494
+ assert_equal(['I.(SI)V'], phase1(['I.(S)V', 'I.(SI)V', 'I.(SII)V'], ['S','I']))
495
+ end
496
+
497
+ def test_ambiguous
498
+ assert_equal(Set.new(%w(I.(SI)V I.(IS)V)),
499
+ Set.new(phase1(%w(I.(SI)V I.(IS)V), %w(S S))))
500
+ end
501
+
502
+ def test_ambiguity_resolution
503
+ assert_equal(['I.()V'], phase1(%w(@Z.()V I.()V), []))
504
+ end
505
+
506
+ def test_error_least_specific
507
+ error_member = Member.new(
508
+ Opcodes.ACC_PUBLIC, wrap('I'), 'foo', [ErrorType.new([['Error']])], wrap('I'),
509
+ MemberKind::METHOD)
510
+ # The method should match
511
+ assert_equal([error_member],
512
+ @lookup.phase1([error_member], [wrap('I')]).to_a)
513
+ # And be least specific
514
+ ok_member = make_method('I.(I)S')
515
+ assert_equal([ok_member],
516
+ @lookup.phase1([error_member, ok_member], [wrap('I')]).to_a)
517
+ end
518
+ end
519
+
520
+ class FieldTest < BaseMethodLookupTest
521
+ def setup
522
+ super
523
+ @a = FakeMirror.new('LA;')
524
+ @b = FakeMirror.new('LB;', @a)
525
+ @scope = JVMScope.new
526
+ @selfType = BaseTypeFuture.new
527
+ @selfType.resolved(@b)
528
+ @scope.selfType_set(@selfType)
529
+ end
530
+
531
+ def test_gather_fields
532
+ a_foo = @a.add_field("foo")
533
+ a_bar = @a.add_field("bar")
534
+ b_foo = @b.add_field("foo")
535
+ foos = @lookup.gatherFields(@b, 'foo').to_a
536
+ assert_equal([b_foo, a_foo], foos)
537
+
538
+ assert_equal([a_bar], @lookup.gatherFields(@b, 'bar').to_a)
539
+ end
540
+
541
+ def test_find_super_field
542
+ @a.add_field("foo")
543
+ future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
544
+ assert_equal("LA;", future.resolve.returnType.asm_type.descriptor)
545
+ end
546
+
547
+ def test_field_override
548
+ @a.add_field("foo")
549
+ @b.add_field("foo")
550
+
551
+ future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
552
+ assert_equal("LB;", future.resolve.returnType.asm_type.descriptor)
553
+ end
554
+
555
+ def test_inaccessible_overrides_accessible
556
+ @selfType.resolved(@a)
557
+ @a.add_field("foo", Opcodes.ACC_PUBLIC)
558
+ @b.add_field("foo", Opcodes.ACC_PRIVATE)
559
+
560
+ future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
561
+ assert_equal("LA;", future.resolve.returnType.asm_type.descriptor)
562
+ end
563
+
564
+ def test_inaccessible
565
+ @a.add_field("foo", Opcodes.ACC_PRIVATE)
566
+ future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
567
+ assert(future.resolve.isError, "Expected error, got #{future.resolve}")
568
+ end
569
+
570
+ def test_field_setter
571
+ @a.add_field("foo")
572
+ future = @lookup.findMethod(@scope, @a, 'foo_set', [@a], nil, nil, false)
573
+ end
574
+ end