Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion lib/typeprof/core/graph/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def destroy(genv)
$box_counts[self.class] -= 1
$box_counts[Box] -= 1
@destroyed = true
destroy_symbol_proc_call_boxes(genv)
@changes.reinstall(genv) # rollback all changes
end

Expand All @@ -43,6 +44,24 @@ def run0(genv, changes)
raise NotImplementedError
end

def add_symbol_proc_call_box(_changes, genv, sym, caller_positionals, caller_keywords = nil)
return if caller_positionals.empty?

recv = caller_positionals.first
positionals = caller_positionals[1..]
@symbol_proc_call_boxes ||= {}
@symbol_proc_call_boxes[[recv, sym, *positionals, caller_keywords]] ||= begin
a_args = ActualArguments.new(positionals, ::Array.new(positionals.size, false), caller_keywords, nil)
MethodCallBox.new(@node, genv, recv, sym, a_args, false)
end
end

def destroy_symbol_proc_call_boxes(genv)
return unless @symbol_proc_call_boxes
@symbol_proc_call_boxes.each_value { |box| box.destroy(genv) }
@symbol_proc_call_boxes = nil
end

def to_s
"#{ self.class.to_s.split("::").last }#{ @id ||= $new_id += 1 }"
end
Expand Down Expand Up @@ -258,6 +277,7 @@ def destroy(genv)
me = genv.resolve_method(@cpath, @singleton, @mid)
me.remove_decl(self)
me.add_run_all_method_call_boxes(genv)
destroy_symbol_proc_call_boxes(genv)
end

def match_arguments?(genv, changes, param_map, a_args, method_type)
Expand Down Expand Up @@ -382,6 +402,8 @@ def resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, f
end
end
end
when Type::Symbol
resolve_symbol_proc(changes, genv, ty.sym, blk_a_args, rbs_blk, param_map0)
end
end
end
Expand All @@ -396,6 +418,13 @@ def resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, f
end
end

def resolve_symbol_proc(changes, genv, sym, blk_a_args, rbs_blk, param_map)
box = add_symbol_proc_call_box(changes, genv, sym, blk_a_args)
return unless box

rbs_blk.return_type.typecheck(genv, changes, box.ret, param_map)
end

def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
if @method_types.size == 1
method_type = @method_types.first
Expand Down Expand Up @@ -1026,7 +1055,10 @@ def run0(genv, changes)
called_mdefs = Set.empty
error_count = 0
resolve(genv, changes) do |me, ty, mid, orig_ty|
if !me
if @node.is_a?(AST::YieldNode) && mid == :call && orig_ty.is_a?(Type::Symbol)
box = add_symbol_proc_call_box(changes, genv, orig_ty.sym, @a_args.positionals, @a_args.keywords)
changes.add_edge(genv, box.ret, @ret) if box
elsif !me
unless @suppress_errors
if error_count < 3
meth = @node.mid_code_range ? :mid_code_range : :code_range
Expand Down
44 changes: 44 additions & 0 deletions scenario/block/symbol_to_proc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## update: test.rbs
class Receiver
def render: (Integer) -> String
def render_kw: (key: Integer) -> Float
end

class Object
def yield_receiver: [R] { (Receiver, Integer) -> R } -> R
end

## update: test.rb
def map_to_i
["1", "2"].map(&:to_i)
end

def yield_to_symbol_proc
yield_receiver(&:render)
end

def apply_to(value)
yield value
end

def yield_from_ruby_method
apply_to("1", &:to_i)
end

def apply_to_kw(value)
yield value, key: 1
end

def yield_from_ruby_method_kw
apply_to_kw(Receiver.new, &:render_kw)
end

## assert: test.rb
class Object
def map_to_i: -> Array[Integer]
def yield_to_symbol_proc: -> String
def apply_to: (String) { (String) -> Integer } -> Integer
def yield_from_ruby_method: -> Integer
def apply_to_kw: (Receiver) { (Receiver) -> Float } -> Float
def yield_from_ruby_method_kw: -> Float
end
Loading