Parameter type includes values assigned via `Hash#[]=` on local variable
まだ誰も着手していません。
- 主要言語
- Ruby
- スター
- 833
- フォーク
- 99
- 平均マージ
- 9時間 30分
- マージ済み PR(30日)
- 12
説明
Steps to reproduce
Analyze the following file with TypeProf.
def foo(options)
options[:name] = "str"
nil
end
foo(Hash.new)
Expected behavior
class Object
def foo: (Hash[untyped, untyped]) -> nil
end
Parameter types should only reflect the types passed from call sites, not values assigned inside the method.
Actual behavior
$ bin/typeprof reproduce.rb
# TypeProf 0.31.1
# reproduce.rb
class Object
def foo: (Hash[:name, String]) -> nil
end
System configuration
Ruby version: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25]
TypeProf version: 753de9b8501f4f7c509e605ea9c9982efa8fc311
Real-world use cases
I noticed this issue when analyzing Action Pack with TypeProf.
The minimum steps required to actually analyze Action Pack are as follows:
$ bin/typeprof tmp/rails/actionpack/test/controller/routing_test.rb \
tmp/rails/actionpack/lib/action_dispatch/routing/route_set.rb \
tmp/rails/actionpack/lib/action_dispatch/journey/formatter.rb > ap.rbs
$ cat ap.rbs | grep url_for | wc -c
13936
$ cat ap.rbs | grep url_for
def url_for: (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], (Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], String] | Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], untyped] | String)?] | Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | :path | :path_params | :person | :port | :protocol | :script_name | :subdomain | :tld_length | :trailing_slash | :use_route | :user | Range[Integer], String] | Hash[:_recall | :action | :anchor | :controller | :domain | :foo | :format | :host | :id | :name | :only_path | :original_script_name | :params | :password | ...(omitted
The parameter type contains a recursive structure such as Hash[:_recall | ..., Hash[:_recall | ..., Hash[:_recall, ...].
I have identified the cause of this as Hash#[]=.
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず reproduce.rb に対して bin/typeprof を実行し、生成されたシグネチャを期待される RBS と比較します。次に TypeProf における Hash#[]= の処理を追跡し、その後 Action Pack のコマンドと route_set.rb、formatter.rb、routing_test.rb の入力を使って、パラメータ型に代入された値や再帰的な Hash 構造が蓄積されなくなっていることを確認します。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- ruby
- 領域
- devtools
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 45/100