typeprof 0.31.1 → 0.33.0

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/doc/report_guide.md +88 -0
  4. data/lib/typeprof/cli/cli.rb +9 -3
  5. data/lib/typeprof/code_range.rb +7 -5
  6. data/lib/typeprof/core/ast/base.rb +31 -6
  7. data/lib/typeprof/core/ast/call.rb +120 -39
  8. data/lib/typeprof/core/ast/const.rb +22 -11
  9. data/lib/typeprof/core/ast/control.rb +62 -32
  10. data/lib/typeprof/core/ast/meta.rb +279 -14
  11. data/lib/typeprof/core/ast/method.rb +82 -24
  12. data/lib/typeprof/core/ast/misc.rb +41 -12
  13. data/lib/typeprof/core/ast/module.rb +38 -4
  14. data/lib/typeprof/core/ast/pattern.rb +51 -23
  15. data/lib/typeprof/core/ast/sig_decl.rb +141 -27
  16. data/lib/typeprof/core/ast/sig_type.rb +113 -32
  17. data/lib/typeprof/core/ast/value.rb +14 -6
  18. data/lib/typeprof/core/ast/variable.rb +17 -4
  19. data/lib/typeprof/core/ast.rb +98 -14
  20. data/lib/typeprof/core/builtin.rb +184 -12
  21. data/lib/typeprof/core/env/method.rb +343 -6
  22. data/lib/typeprof/core/env/method_entity.rb +18 -15
  23. data/lib/typeprof/core/env/module_entity.rb +116 -18
  24. data/lib/typeprof/core/env/static_read.rb +4 -4
  25. data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
  26. data/lib/typeprof/core/env/value_entity.rb +25 -3
  27. data/lib/typeprof/core/env.rb +113 -23
  28. data/lib/typeprof/core/graph/box.rb +508 -63
  29. data/lib/typeprof/core/graph/change_set.rb +64 -46
  30. data/lib/typeprof/core/graph/filter.rb +8 -5
  31. data/lib/typeprof/core/graph/vertex.rb +20 -19
  32. data/lib/typeprof/core/service.rb +340 -24
  33. data/lib/typeprof/core/type.rb +41 -7
  34. data/lib/typeprof/core/util.rb +6 -0
  35. data/lib/typeprof/lsp/messages.rb +5 -0
  36. data/lib/typeprof/lsp/server.rb +35 -4
  37. data/lib/typeprof/version.rb +1 -1
  38. metadata +3 -2
@@ -46,7 +46,7 @@ module TypeProf::Core
46
46
  def initialize(raw_node, rhs, lenv)
47
47
  super(raw_node, lenv)
48
48
  @var = raw_node.name
49
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
49
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
50
50
  @rhs = rhs
51
51
  end
52
52
 
@@ -63,11 +63,24 @@ module TypeProf::Core
63
63
  val
64
64
  end
65
65
 
66
+ def install_pattern0(genv, subject)
67
+ install0(genv)
68
+ @changes.add_edge(genv, subject, @rhs.ret)
69
+ subject
70
+ end
71
+
66
72
  def retrieve_at(pos, &blk)
67
73
  yield self if @var_code_range && @var_code_range.include?(pos)
68
74
  super(pos, &blk)
69
75
  end
70
76
 
77
+ def narrowings
78
+ @narrowings ||= [
79
+ Narrowing.new({ @var => Narrowing::NilConstraint.new(false) }),
80
+ Narrowing.new({ @var => Narrowing::NilConstraint.new(true) }),
81
+ ]
82
+ end
83
+
71
84
  def modified_vars(tbl, vars)
72
85
  vars << self.var if tbl.include?(self.var)
73
86
  end
@@ -109,7 +122,7 @@ module TypeProf::Core
109
122
  def initialize(raw_node, rhs, lenv)
110
123
  super(raw_node, lenv)
111
124
  @var = raw_node.name
112
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
125
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
113
126
  @rhs = rhs
114
127
  end
115
128
 
@@ -191,7 +204,7 @@ module TypeProf::Core
191
204
  def initialize(raw_node, rhs, lenv)
192
205
  super(raw_node, lenv)
193
206
  @var = raw_node.name
194
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
207
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
195
208
  @rhs = rhs
196
209
  end
197
210
 
@@ -264,7 +277,7 @@ module TypeProf::Core
264
277
  def initialize(raw_node, rhs, lenv)
265
278
  super(raw_node, lenv)
266
279
  @var = raw_node.name
267
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
280
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
268
281
  @rhs = rhs
269
282
  end
270
283
 
@@ -1,6 +1,6 @@
1
1
  module TypeProf::Core
2
2
  class AST
3
- def self.parse_rb(path, src)
3
+ def self.parse_rb(path, src, position_encoding)
4
4
  result = Prism.parse(src)
5
5
 
6
6
  return nil unless result.errors.empty?
@@ -10,19 +10,58 @@ module TypeProf::Core
10
10
 
11
11
  raise unless raw_scope.type == :program_node
12
12
 
13
- Fiber[:comments] = result.comments
13
+ prism_source = result.source
14
+ file_context = FileContext.new(path, position_encoding, prism_source, result.comments)
14
15
 
15
16
  cref = CRef::Toplevel
16
- lenv = LocalEnv.new(path, cref, {}, [])
17
+ lenv = LocalEnv.new(file_context, cref, {}, [])
17
18
 
18
- ProgramNode.new(raw_scope, lenv)
19
+ ignore_ranges = collect_ignore_ranges(result)
20
+ ProgramNode.new(raw_scope, lenv, ignore_ranges: ignore_ranges)
19
21
  end
20
22
 
21
- #: (untyped, TypeProf::Core::LocalEnv, ?bool) -> TypeProf::Core::AST::Node
22
- def self.create_node(raw_node, lenv, use_result = true)
23
+ # Collect line ranges marked with `# typeprof:ignore` comments.
24
+ # Each range is suppressed in ProgramNode#each_diagnostic.
25
+ #
26
+ # Inline form (suppresses the line containing the comment):
27
+ # foo(1, 2) # typeprof:ignore
28
+ #
29
+ # Block form (suppresses lines between :start and :end):
30
+ # # typeprof:ignore:start
31
+ # foo(1, 2)
32
+ # # typeprof:ignore:end
33
+ #
34
+ # An unmatched `:start` extends to the end of the file.
35
+ IGNORE_RE = /\A#\s*typeprof:ignore\s*\z/
36
+ IGNORE_START_RE = /\A#\s*typeprof:ignore:start\s*\z/
37
+ IGNORE_END_RE = /\A#\s*typeprof:ignore:end\s*\z/
38
+ def self.collect_ignore_ranges(prism_result)
39
+ ranges = []
40
+ start_line = nil
41
+ prism_result.comments.each do |c|
42
+ text = c.location.slice
43
+ line = c.location.start_line
44
+ if text.match?(IGNORE_START_RE)
45
+ start_line ||= line
46
+ elsif text.match?(IGNORE_END_RE)
47
+ if start_line
48
+ ranges << (start_line..line)
49
+ start_line = nil
50
+ end
51
+ elsif text.match?(IGNORE_RE)
52
+ ranges << (line..line)
53
+ end
54
+ end
55
+ ranges << (start_line..Float::INFINITY) if start_line
56
+ ranges
57
+ end
58
+
59
+ #: (untyped, TypeProf::Core::LocalEnv, ?bool, ?bool) -> TypeProf::Core::AST::Node
60
+ def self.create_node(raw_node, lenv, use_result = true, allow_meta = false)
23
61
  while true
24
62
  case raw_node.type
25
63
  when :parentheses_node
64
+ return DummyNilNode.new(lenv.code_range_from_node(raw_node), lenv) if raw_node.body.nil?
26
65
  raw_node = raw_node.body
27
66
  when :implicit_node
28
67
  raw_node = raw_node.value
@@ -64,7 +103,13 @@ module TypeProf::Core
64
103
  when :constant_read_node, :constant_path_node
65
104
  ConstantReadNode.new(raw_node, lenv)
66
105
  when :constant_write_node, :constant_path_write_node
67
- ConstantWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
106
+ if (members = detect_struct_new(raw_node.value))
107
+ StructNewNode.new(raw_node, members, :struct, lenv)
108
+ elsif (members = detect_data_define(raw_node.value))
109
+ StructNewNode.new(raw_node, members, :data, lenv)
110
+ else
111
+ ConstantWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
112
+ end
68
113
  when :constant_operator_write_node
69
114
  read = ConstantReadNode.new(raw_node, lenv)
70
115
  rhs = OperatorNode.new(raw_node, read, lenv)
@@ -132,6 +177,7 @@ module TypeProf::Core
132
177
  when :class_variable_operator_write_node
133
178
  read = ClassVariableReadNode.new(raw_node, lenv)
134
179
  rhs = OperatorNode.new(raw_node, read, lenv)
180
+ ClassVariableWriteNode.new(raw_node, rhs, lenv)
135
181
  when :class_variable_or_write_node
136
182
  read = ClassVariableReadNode.new(raw_node, lenv)
137
183
  rhs = OrNode.new(raw_node, read, raw_node.value, lenv)
@@ -233,15 +279,22 @@ module TypeProf::Core
233
279
  when :forwarding_super_node then ForwardingSuperNode.new(raw_node, lenv)
234
280
  when :yield_node then YieldNode.new(raw_node, lenv)
235
281
  when :call_node
236
- if !raw_node.receiver
237
- # TODO: handle them only when it is directly under class or module
282
+ if allow_meta && !raw_node.receiver && !lenv.cref.mid && [:class, :metaclass].include?(lenv.cref.scope_level)
238
283
  case raw_node.name
239
284
  when :include
240
285
  return IncludeMetaNode.new(raw_node, lenv)
286
+ when :extend
287
+ return ExtendMetaNode.new(raw_node, lenv)
241
288
  when :attr_reader
242
289
  return AttrReaderMetaNode.new(raw_node, lenv)
290
+ when :attr_writer
291
+ return AttrWriterMetaNode.new(raw_node, lenv)
243
292
  when :attr_accessor
244
293
  return AttrAccessorMetaNode.new(raw_node, lenv)
294
+ when :module_function
295
+ if raw_node.arguments.nil?
296
+ return ModuleFunctionMetaNode.new(raw_node, lenv)
297
+ end
245
298
  end
246
299
  end
247
300
  CallNode.new(raw_node, lenv)
@@ -252,7 +305,7 @@ module TypeProf::Core
252
305
  end
253
306
 
254
307
  def self.create_target_node(raw_node, lenv)
255
- dummy_node = DummyRHSNode.new(TypeProf::CodeRange.from_node(raw_node.location), lenv)
308
+ dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
256
309
  case raw_node.type
257
310
  when :local_variable_target_node
258
311
  LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
@@ -305,7 +358,7 @@ module TypeProf::Core
305
358
  when :pinned_expression_node then PinnedPatternNode.new(raw_node, lenv)
306
359
 
307
360
  when :local_variable_target_node
308
- dummy_node = DummyRHSNode.new(TypeProf::CodeRange.from_node(raw_node.location), lenv)
361
+ dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
309
362
  LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
310
363
 
311
364
  when :constant_read_node, :constant_path_node
@@ -364,11 +417,12 @@ module TypeProf::Core
364
417
  return cpath + names.reverse if cpath
365
418
  end
366
419
 
367
- def self.parse_rbs(path, src)
420
+ def self.parse_rbs(path, src, position_encoding)
368
421
  _buffer, _directives, raw_decls = RBS::Parser.parse_signature(src)
369
422
 
370
423
  cref = CRef::Toplevel
371
- lenv = LocalEnv.new(path, cref, {}, [])
424
+ file_context = FileContext.new(path, position_encoding)
425
+ lenv = LocalEnv.new(file_context, cref, {}, [])
372
426
 
373
427
  raw_decls.map do |raw_decl|
374
428
  AST.create_rbs_decl(raw_decl, lenv)
@@ -385,7 +439,10 @@ module TypeProf::Core
385
439
  SigInterfaceNode.new(raw_decl, lenv)
386
440
  when RBS::AST::Declarations::Constant
387
441
  SigConstNode.new(raw_decl, lenv)
388
- when RBS::AST::Declarations::AliasDecl
442
+ when RBS::AST::Declarations::ClassAlias
443
+ SigClassAliasNode.new(raw_decl, lenv)
444
+ when RBS::AST::Declarations::ModuleAlias
445
+ SigModuleAliasNode.new(raw_decl, lenv)
389
446
  when RBS::AST::Declarations::TypeAlias
390
447
  SigTypeAliasNode.new(raw_decl, lenv)
391
448
  # TODO: check
@@ -405,6 +462,7 @@ module TypeProf::Core
405
462
  when RBS::AST::Members::Prepend
406
463
  SigPrependNode.new(raw_decl, lenv)
407
464
  when RBS::AST::Members::Extend
465
+ SigExtendNode.new(raw_decl, lenv)
408
466
  when RBS::AST::Members::Public
409
467
  when RBS::AST::Members::Private
410
468
  when RBS::AST::Members::Alias
@@ -481,5 +539,31 @@ module TypeProf::Core
481
539
  raise "unknown RBS type: #{ raw_decl.class }"
482
540
  end
483
541
  end
542
+
543
+ def self.detect_struct_new(raw_value)
544
+ return nil unless raw_value.type == :call_node
545
+ return nil unless raw_value.name == :new
546
+ recv = raw_value.receiver
547
+ return nil unless recv&.type == :constant_read_node && recv.name == :Struct
548
+ extract_symbol_args(raw_value)
549
+ end
550
+
551
+ def self.detect_data_define(raw_value)
552
+ return nil unless raw_value.type == :call_node
553
+ return nil unless raw_value.name == :define
554
+ recv = raw_value.receiver
555
+ return nil unless recv&.type == :constant_read_node && recv.name == :Data
556
+ extract_symbol_args(raw_value)
557
+ end
558
+
559
+ def self.extract_symbol_args(raw_call)
560
+ return nil unless raw_call.arguments
561
+ members = []
562
+ raw_call.arguments.arguments.each do |arg|
563
+ return nil unless arg.type == :symbol_node
564
+ members << arg.value.to_sym
565
+ end
566
+ members
567
+ end
484
568
  end
485
569
  end
@@ -69,6 +69,20 @@ module TypeProf::Core
69
69
  else
70
70
  false
71
71
  end
72
+ elsif a_args.positionals.size == 3
73
+ # ary[start, len] = val
74
+ # Use SplatBox to extract element types from the assigned value
75
+ elem_vtx = case ty
76
+ when Type::Array
77
+ ty.get_elem(@genv)
78
+ when Type::Instance
79
+ ty.mod == @genv.mod_ary ? ty.args[0] : nil
80
+ end
81
+ return false unless elem_vtx
82
+ val = a_args.positionals[2]
83
+ splat_ret = changes.add_splat_box(@genv, val).ret
84
+ changes.add_edge(@genv, splat_ret, elem_vtx)
85
+ true
72
86
  else
73
87
  false
74
88
  end
@@ -90,7 +104,7 @@ module TypeProf::Core
90
104
  def hash_aref(changes, node, ty, a_args, ret)
91
105
  if a_args.positionals.size == 1
92
106
  case ty
93
- when Type::Hash, Type::Record
107
+ when Type::Hash
94
108
  idx = node.positional_args[0]
95
109
  idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
96
110
  value = ty.get_value(idx)
@@ -101,6 +115,20 @@ module TypeProf::Core
101
115
  changes.add_edge(@genv, Source.new(), ret)
102
116
  end
103
117
  true
118
+ when Type::Record
119
+ idx = node.positional_args[0]
120
+ idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
121
+ value = ty.get_value(idx)
122
+ if value
123
+ changes.add_edge(@genv, value, ret)
124
+ else
125
+ changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
126
+ end
127
+ # Symbol variable access - add nil possibility
128
+ if idx.nil?
129
+ changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
130
+ end
131
+ true
104
132
  else
105
133
  false
106
134
  end
@@ -125,6 +153,15 @@ module TypeProf::Core
125
153
  end
126
154
  changes.add_edge(@genv, val, ret)
127
155
  true
156
+ when Type::Record
157
+ val = a_args.positionals[1]
158
+ idx = node.positional_args[0]
159
+ if idx.is_a?(AST::SymbolNode)
160
+ field_vtx = ty.get_value(idx.lit)
161
+ changes.add_edge(@genv, val, field_vtx) if field_vtx
162
+ end
163
+ changes.add_edge(@genv, val, ret)
164
+ true
128
165
  else
129
166
  false
130
167
  end
@@ -133,19 +170,154 @@ module TypeProf::Core
133
170
  end
134
171
  end
135
172
 
173
+ def object_method(changes, node, ty, a_args, ret)
174
+ if a_args.positionals.size == 1
175
+ sym_node = node.positional_args[0]
176
+ if sym_node.is_a?(AST::SymbolNode)
177
+ method_ty = Type::Method.new(@genv, ty, sym_node.lit)
178
+ changes.add_edge(@genv, Source.new(method_ty), ret)
179
+ return true
180
+ end
181
+ end
182
+ false
183
+ end
184
+
185
+ def method_call(changes, node, ty, a_args, ret)
186
+ case ty
187
+ when Type::Method
188
+ recv = Source.new(ty.recv_ty)
189
+ box = changes.add_method_call_box(@genv, recv, ty.mid, a_args, false)
190
+ changes.add_edge(@genv, box.ret, ret)
191
+ true
192
+ else
193
+ false
194
+ end
195
+ end
196
+
197
+ def kernel_send(changes, node, ty, a_args, ret)
198
+ return false if a_args.positionals.empty?
199
+
200
+ if a_args.splat_flags[0]
201
+ # send(*array) case: extract method name and args from array elements
202
+ splat_vtx = a_args.positionals[0]
203
+ changes.add_edge(@genv, splat_vtx, changes.target)
204
+
205
+ rest_positionals = a_args.positionals[1..]
206
+ rest_splat_flags = a_args.splat_flags[1..]
207
+
208
+ splat_vtx.each_type do |ary_ty|
209
+ next unless ary_ty.is_a?(Type::Array)
210
+
211
+ if ary_ty.elems && ary_ty.elems.size >= 1
212
+ # Tuple: use per-element precision
213
+ method_name_vtx = ary_ty.elems[0]
214
+ changes.add_edge(@genv, method_name_vtx, changes.target)
215
+
216
+ elem_args = ary_ty.elems[1..] + rest_positionals
217
+ elem_flags = ::Array.new(ary_ty.elems.size - 1, false) + rest_splat_flags
218
+ send_a_args = ActualArguments.new(elem_args, elem_flags, a_args.keywords, a_args.block)
219
+
220
+ method_name_vtx.each_type do |sym_ty|
221
+ if sym_ty.is_a?(Type::Symbol)
222
+ recv = Source.new(ty)
223
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
224
+ changes.add_edge(@genv, box.ret, ret)
225
+ end
226
+ end
227
+ else
228
+ # Non-tuple array: use unified element type for method name
229
+ elem_vtx = ary_ty.get_elem(@genv)
230
+ next unless elem_vtx
231
+ changes.add_edge(@genv, elem_vtx, changes.target)
232
+
233
+ send_a_args = ActualArguments.new(rest_positionals, rest_splat_flags, a_args.keywords, a_args.block)
234
+
235
+ elem_vtx.each_type do |sym_ty|
236
+ if sym_ty.is_a?(Type::Symbol)
237
+ recv = Source.new(ty)
238
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
239
+ changes.add_edge(@genv, box.ret, ret)
240
+ end
241
+ end
242
+ end
243
+ end
244
+ else
245
+ # send(:sym, ...) case
246
+ changes.add_edge(@genv, a_args.positionals[0], changes.target)
247
+ send_a_args = ActualArguments.new(
248
+ a_args.positionals[1..],
249
+ a_args.splat_flags[1..],
250
+ a_args.keywords,
251
+ a_args.block,
252
+ )
253
+ a_args.positionals[0].each_type do |sym_ty|
254
+ if sym_ty.is_a?(Type::Symbol)
255
+ recv = Source.new(ty)
256
+ box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
257
+ changes.add_edge(@genv, box.ret, ret)
258
+ end
259
+ end
260
+ end
261
+ true
262
+ end
263
+
264
+ def kernel_array(changes, node, ty, a_args, ret)
265
+ return false unless a_args.positionals.size == 1
266
+
267
+ arg_vtx = a_args.positionals[0]
268
+ elem_vtx = Vertex.new(node)
269
+ handled = false
270
+ needs_elem_wrap = false
271
+
272
+ arg_vtx.each_type do |arg_ty|
273
+ handled = true
274
+ case arg_ty
275
+ when Type::Instance
276
+ if arg_ty.mod == @genv.mod_range && arg_ty.args && !arg_ty.args.empty?
277
+ changes.add_edge(@genv, arg_ty.args[0], elem_vtx)
278
+ needs_elem_wrap = true
279
+ elsif arg_ty.mod == @genv.mod_ary
280
+ changes.add_edge(@genv, Source.new(arg_ty), ret)
281
+ else
282
+ changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
283
+ needs_elem_wrap = true
284
+ end
285
+ when Type::Array
286
+ changes.add_edge(@genv, Source.new(arg_ty), ret)
287
+ else
288
+ changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
289
+ needs_elem_wrap = true
290
+ end
291
+ end
292
+
293
+ return false unless handled
294
+
295
+ if needs_elem_wrap
296
+ ary_ty = @genv.gen_ary_type(elem_vtx)
297
+ changes.add_edge(@genv, Source.new(ary_ty), ret)
298
+ end
299
+ true
300
+ end
301
+
136
302
  def deploy
137
- {
138
- class_new: [[:Class], false, :new],
139
- object_class: [[:Object], false, :class],
140
- proc_call: [[:Proc], false, :call],
141
- array_aref: [[:Array], false, :[]],
142
- array_aset: [[:Array], false, :[]=],
143
- array_push: [[:Array], false, :<<],
144
- hash_aref: [[:Hash], false, :[]],
145
- hash_aset: [[:Hash], false, :[]=],
146
- }.each do |key, (cpath, singleton, mid)|
303
+ [
304
+ [method(:class_new), [:Class], false, :new],
305
+ [method(:object_class), [:Object], false, :class],
306
+ [method(:proc_call), [:Proc], false, :call],
307
+ [method(:array_aref), [:Array], false, :[]],
308
+ [method(:array_aset), [:Array], false, :[]=],
309
+ [method(:array_push), [:Array], false, :<<],
310
+ [method(:hash_aref), [:Hash], false, :[]],
311
+ [method(:hash_aset), [:Hash], false, :[]=],
312
+ [method(:object_method), [:Kernel], false, :method],
313
+ [method(:method_call), [:Method], false, :call],
314
+ [method(:kernel_send), [:BasicObject], false, :__send__],
315
+ [method(:kernel_send), [:Kernel], false, :public_send],
316
+ [method(:kernel_send), [:Kernel], false, :send],
317
+ [method(:kernel_array), [:Kernel], false, :Array],
318
+ ].each do |builtin, cpath, singleton, mid|
147
319
  me = @genv.resolve_method(cpath, singleton, mid)
148
- me.builtin = method(key)
320
+ me.builtin = builtin
149
321
  end
150
322
  end
151
323
  end