mirah 0.1.0.pre-java → 0.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
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