├── .devcontainer └── devcontainer.json ├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── bin └── typeprof ├── doc ├── doc.ja.md └── doc.md ├── lib ├── typeprof.rb └── typeprof │ ├── cli.rb │ ├── cli │ ├── cli.rb │ └── typeprof.conf.jsonc │ ├── code_range.rb │ ├── core.rb │ ├── core │ ├── ast.rb │ ├── ast │ │ ├── base.rb │ │ ├── call.rb │ │ ├── const.rb │ │ ├── control.rb │ │ ├── meta.rb │ │ ├── method.rb │ │ ├── misc.rb │ │ ├── module.rb │ │ ├── pattern.rb │ │ ├── sig_decl.rb │ │ ├── sig_type.rb │ │ ├── value.rb │ │ └── variable.rb │ ├── builtin.rb │ ├── env.rb │ ├── env │ │ ├── method.rb │ │ ├── method_entity.rb │ │ ├── module_entity.rb │ │ ├── static_read.rb │ │ ├── type_alias_entity.rb │ │ └── value_entity.rb │ ├── graph │ │ ├── box.rb │ │ ├── change_set.rb │ │ ├── filter.rb │ │ └── vertex.rb │ ├── service.rb │ ├── type.rb │ └── util.rb │ ├── diagnostic.rb │ ├── lsp.rb │ ├── lsp │ ├── messages.rb │ ├── server.rb │ ├── text.rb │ └── util.rb │ └── version.rb ├── scenario ├── args │ ├── forwarding_arguments.rb │ ├── keyword-twice.rb │ ├── keyword_splat.rb │ ├── no-keyword.rb │ ├── positionals_rb_to_rb1.rb │ ├── positionals_rb_to_rb2.rb │ ├── positionals_rb_to_rb3.rb │ ├── positionals_rb_to_rb_block.rb │ ├── positionals_rb_to_rbs.rb │ ├── positionals_rbs_to_rb.rb │ ├── positionals_rbs_to_rb_block.rb │ ├── splat-twice.rb │ ├── splat_rb_to_rb.rb │ └── splat_rbs_to_rb.rb ├── array │ ├── basic1.rb │ ├── basic2.rb │ ├── push.rb │ ├── rbs_tuple.rb │ ├── rbs_tuple2.rb │ ├── splat.rb │ ├── splat2.rb │ ├── tuple_aref.rb │ └── tuple_aset.rb ├── block │ ├── anonymous_block_forwarding.rb │ ├── basic1.rb │ ├── basic2.rb │ ├── block_pass.rb │ ├── it.rb │ ├── numbered_parameter.rb │ ├── rbs_block.rb │ ├── rbs_block2.rb │ ├── rbs_block3.rb │ ├── rbs_block4.rb │ ├── rbs_block5.rb │ ├── rbs_block6.rb │ └── rbs_block7.rb ├── class │ ├── basic1.rb │ ├── basic2.rb │ ├── circular.rb │ ├── dynamic.rb │ ├── include-hack.rb │ ├── initialize.rb │ ├── initialize2.rb │ ├── initialize3.rb │ ├── module.rb │ ├── module2.rb │ ├── rbs_class.rb │ ├── rbs_module.rb │ ├── rbs_module2.rb │ ├── rbs_module3.rb │ ├── rbs_self_types1.rb │ ├── rbs_self_types2.rb │ ├── rbs_self_types3.rb │ ├── self-in-cbase.rb │ ├── singleton_class.rb │ └── unknown-cbase.rb ├── const │ ├── basic1.rb │ ├── basic2.rb │ ├── circular.rb │ ├── dynamic.rb │ ├── module_const.rb │ ├── rbs_const.rb │ ├── resolve.rb │ ├── superclass1.rb │ ├── superclass2.rb │ ├── superclass3.rb │ └── superclass4.rb ├── control │ ├── and.rb │ ├── begin-variable-tracking.rb │ ├── begin.rb │ ├── bot.rb │ ├── bot2.rb │ ├── bot3.rb │ ├── bot4.rb │ ├── branch.rb │ ├── break.rb │ ├── case.rb │ ├── elsif.rb │ ├── empty.rb │ ├── ensure.rb │ ├── loop.rb │ ├── loop2.rb │ ├── next-in-loop.rb │ ├── next.rb │ ├── next2.rb │ ├── next3.rb │ ├── or.rb │ ├── raise-bot.rb │ ├── redo.rb │ ├── rescue-assign.rb │ ├── rescue-splat.rb │ ├── rescue.rb │ ├── retry.rb │ ├── return.rb │ └── return2.rb ├── definitions │ ├── definition-rbs.rb │ ├── definition.rb │ └── definition_multibyte_characters.rb ├── diagnostics │ ├── argumenterror.rb │ ├── nomethoderror.rb │ └── reuse.rb ├── flow │ ├── is_a.rb │ ├── is_a2.rb │ ├── is_a_module.rb │ ├── ivar.rb │ ├── nil.rb │ ├── nil2.rb │ ├── or.rb │ ├── return_if.rb │ └── while.rb ├── hash │ ├── basic1.rb │ ├── hash-splat.rb │ └── implicit.rb ├── incremental │ ├── add-included-module.rb │ ├── basic1.rb │ ├── basic2.rb │ ├── basic3.rb │ ├── basic4.rb │ ├── basic5.rb │ ├── change-included-module.rb │ ├── change-superclass.rb │ └── remove-included-module2.rb ├── known-issues │ ├── alias-global-variable.rb │ ├── array-zip-type.rb │ ├── block_optionals.rb │ ├── break-in-loop.rb │ ├── cbase-is-not-class.rb │ ├── check-return-type.rb │ ├── const-scope.rb │ ├── constant-path.rb │ ├── dynamic-include.rb │ ├── fcall-include.rb │ ├── forwarding-arguments.rb │ ├── keywords.rb │ ├── multi-const-write.rb │ ├── multi_arg_break.rb │ ├── multi_target_arg.rb │ ├── multi_target_block_arg.rb │ ├── optional-type-param.rb │ ├── retry.rb │ ├── singleton-class.rb │ ├── singleton-method.rb │ ├── splat-on-non-array.rb │ ├── struct.rb │ └── unsupported-arg.rb ├── lambda │ └── basic1.rb ├── meta │ ├── attr_accessor.rb │ └── attr_reader.rb ├── method │ ├── alias.rb │ ├── attrasgn.rb │ ├── block-arg.rb │ ├── change-number-of-arguments.rb │ ├── empty_def.rb │ ├── function.rb │ ├── keywords.rb │ ├── mid_code_range.rb │ ├── multi_args.rb │ ├── no_args.rb │ ├── prevent-reuse.rb │ ├── rbs_alias.rb │ ├── reuse-alias.rb │ ├── safe-navigation.rb │ ├── self-alias.rb │ ├── singleton.rb │ ├── splat-arg.rb │ ├── subclass-methods.rb │ └── undef.rb ├── misc │ ├── alias_gvar.rb │ ├── argv.rb │ ├── ast_glitch.rb │ ├── ast_glitch2.rb │ ├── bot-diagnostics.rb │ ├── class_method.rb │ ├── complex.rb │ ├── define_method_return.rb │ ├── defined.rb │ ├── dstr.rb │ ├── dsym.rb │ ├── fcall-for-subclass-methods.rb │ ├── flip_flop.rb │ ├── for.rb │ ├── is_a.rb │ ├── match_asgn.rb │ ├── mix-const.rb │ ├── op_asgn1.rb │ ├── op_asgn_or.rb │ ├── post-exec.rb │ ├── proc.rb │ ├── range.rb │ ├── rational.rb │ ├── regexp.rb │ ├── set.rb │ ├── source_encoding.rb │ ├── source_file.rb │ ├── source_line.rb │ ├── stmts_diff.rb │ ├── super-with-alias.rb │ ├── super.rb │ └── toplevel-return.rb ├── patterns │ ├── alt_pat.rb │ ├── array_pat.rb │ ├── capture.rb │ ├── const_pat.rb │ ├── find_pat.rb │ ├── hash_pat.rb │ ├── if_pat.rb │ ├── in_match.rb │ ├── literal_pat.rb │ ├── pin_pat.rb │ ├── range_pat.rb │ ├── right_assign.rb │ └── var_pat.rb ├── rbs │ ├── any.rb │ ├── attr.rb │ ├── basic1.rb │ ├── basic2.rb │ ├── block.rb │ ├── change-scope.rb │ ├── change-scope2.rb │ ├── change-superclass.rb │ ├── change-superclass2.rb │ ├── check-block-return.rb │ ├── check-return-type.rb │ ├── check-return-type2.rb │ ├── check-return-type3.rb │ ├── check-return-type4.rb │ ├── check-return-type5.rb │ ├── inline-hover.rb │ ├── inline.rb │ ├── interface1.rb │ ├── interface2.rb │ ├── module1.rb │ ├── module2.rb │ ├── module3.rb │ ├── no-overload.rb │ ├── no-type-var.rb │ ├── param1.rb │ ├── param2.rb │ ├── param3.rb │ ├── param4.rb │ ├── param5.rb │ ├── param6.rb │ ├── param7.rb │ ├── recursive1.rb │ ├── recursive2.rb │ ├── remove-class.rb │ ├── self-types.rb │ ├── superclass1.rb │ ├── superclass2.rb │ ├── symbol.rb │ ├── type-alias.rb │ ├── type-alias2.rb │ ├── type-var1.rb │ ├── type-var2.rb │ └── untyped-for-overload.rb ├── regressions │ ├── array-as-self.rb │ ├── array-zip.rb │ ├── avoid-infinite-loop-2.rb │ ├── avoid-infinite-loop-3.rb │ ├── avoid-infinite-loop-4.rb │ ├── avoid-infinite-loop.rb │ ├── double-edge-record-block.rb │ ├── iasgn-multi-edge.rb │ ├── include-enumerable.rb │ ├── ivar-stuck-case.rb │ ├── multi-next.rb │ ├── multi_edge_to_gvar.rb │ ├── self-type-var.rb │ └── splat-block.rb ├── service │ ├── code_lens.rb │ ├── code_lens_update.rb │ ├── completion_dot.rb │ ├── completion_dot_module.rb │ ├── definition.rb │ ├── hover.rb │ ├── hover2.rb │ ├── hover3.rb │ ├── hover4.rb │ ├── references.rb │ ├── references2.rb │ ├── rename.rb │ ├── rename2.rb │ ├── rename3.rb │ └── rename4.rb └── variable │ ├── and_write.rb │ ├── cvar.rb │ ├── dvar.rb │ ├── dvar2.rb │ ├── gvar.rb │ ├── ivar.rb │ ├── ivar2.rb │ ├── ivar3.rb │ ├── masgn-non-array.rb │ ├── masgn.rb │ ├── masgn2.rb │ ├── masgn3.rb │ ├── operator_write.rb │ ├── or_write.rb │ ├── special-vars.rb │ ├── uninitialized_ivar.rb │ └── uninitialized_lvar.rb ├── sig ├── polyfill.rbs └── typeprof.rbs ├── test ├── cli_test.rb ├── code_range_test.rb ├── diagnostic_test.rb ├── fixtures │ ├── basic │ │ ├── basic.rb │ │ └── typeprof.conf.json │ ├── rbs_collection_test │ │ ├── .gitignore │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── dummy_gem_source │ │ │ └── my_dummy_gem │ │ │ │ ├── lib │ │ │ │ └── my_dummy_gem.rb │ │ │ │ └── my_dummy_gem.gemspec │ │ ├── dummy_rbs_collection │ │ │ └── my_dummy_gem │ │ │ │ └── 1.0 │ │ │ │ └── my_dummy_gem.rbs │ │ ├── rbs_collection.lock.yaml │ │ ├── rbs_collection.yaml │ │ └── test.rb │ ├── syntax_error │ │ ├── syntax_error.rb │ │ └── syntax_error.rbs │ └── type_error │ │ ├── type_error.rb │ │ └── type_error.rbs ├── helper.rb ├── lsp │ ├── lsp_test.rb │ └── text_test.rb ├── scenario_compiler.rb └── scenario_test.rb ├── tool ├── dog_bench.rb └── scenario_runner.rb ├── typeprof.conf.jsonc └── typeprof.gemspec /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/ruby 3 | { 4 | "name": "typeprof", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | // "forwardPorts": [], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | // "postCreateCommand": "ruby --version", 16 | 17 | "onCreateCommand": "gem install rbs", 18 | 19 | // Configure tool-specific properties. 20 | "customizations": { 21 | "vscode": { 22 | "settings": { 23 | "typeprof.server.path": "/workspaces/typeprof/bin/typeprof", 24 | "files.associations": { 25 | "typeprof.conf.json": "jsonc" 26 | } 27 | }, 28 | "extensions": [ 29 | "mame.ruby-typeprof" 30 | ] 31 | } 32 | } 33 | 34 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 35 | // "remoteUser": "root" 36 | } 37 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for more information: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | # https://containers.dev/guide/dependabot 6 | 7 | version: 2 8 | updates: 9 | - package-ecosystem: "devcontainers" 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Ruby 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: 8 | # # This job runs at 00:00 on Friday. 9 | - cron: '0 15 * * 5' 10 | 11 | jobs: 12 | ruby-versions: 13 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 14 | with: 15 | engine: cruby-truffleruby 16 | min_version: 3.2 17 | 18 | build: 19 | needs: ruby-versions 20 | name: build (${{ matrix.ruby }}) 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} 25 | include: 26 | - ruby: "3.3" 27 | rubyopt: "--enable-frozen-string-literal" 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Set up Ruby 32 | uses: ruby/setup-ruby@v1 33 | with: 34 | ruby-version: ${{ matrix.ruby }} 35 | - name: Bundle install 36 | run: | 37 | bundle install 38 | - name: Run the test suite 39 | run: | 40 | bundle exec rake TESTOPT=-v RUBYOPT="${{ matrix.rubyopt }}" 41 | if: ${{ !startsWith(matrix.ruby, 'truffle') }} 42 | - name: Run the dog bench 43 | run: | 44 | bundle exec ruby tool/dog_bench.rb 45 | if: ${{ !startsWith(matrix.ruby, 'truffle') }} 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp/ 2 | /pkg/ 3 | dog_bench.stackprof.dump 4 | dog_bench.pf2profile 5 | dog_bench.json -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | #if ENV["RBS_VERSION"] 4 | gem "rbs", github: "ruby/rbs", ref: ENV["RBS_VERSION"] 5 | #else 6 | # # Specify your gem's dependencies in typeprof.gemspec 7 | # gemspec 8 | #end 9 | 10 | gem "prism", ">= 1.4.0" 11 | 12 | group :development do 13 | gem "rake" 14 | gem "stackprof", platforms: :mri 15 | gem "test-unit" 16 | gem "simplecov" 17 | gem "simplecov-html" 18 | gem "coverage-helpers" 19 | end 20 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: https://github.com/ruby/rbs.git 3 | revision: bcc737da3c8c625d55d9b8856d9b8399b92a32d4 4 | specs: 5 | rbs (3.5.1) 6 | logger 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | coverage-helpers (1.0.0) 12 | docile (1.4.0) 13 | logger (1.6.0) 14 | power_assert (2.0.3) 15 | prism (1.4.0) 16 | rake (13.2.1) 17 | simplecov (0.22.0) 18 | docile (~> 1.1) 19 | simplecov-html (~> 0.11) 20 | simplecov_json_formatter (~> 0.1) 21 | simplecov-html (0.12.3) 22 | simplecov_json_formatter (0.1.4) 23 | stackprof (0.2.26) 24 | test-unit (3.6.2) 25 | power_assert 26 | 27 | PLATFORMS 28 | ruby 29 | x86_64-linux 30 | 31 | DEPENDENCIES 32 | coverage-helpers 33 | prism (>= 1.4.0) 34 | rake 35 | rbs! 36 | simplecov 37 | simplecov-html 38 | stackprof 39 | test-unit 40 | 41 | BUNDLED WITH 42 | 2.6.8 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Yusuke Endoh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeProf 2 | 3 | An experimental type-level Ruby interpreter for testing and understanding Ruby code. 4 | 5 | ## Installation 6 | 7 | Install via RubyGems. 8 | 9 | ```sh 10 | $ gem install typeprof 11 | ``` 12 | 13 | ### Requirements 14 | 15 | TypeProf supports Ruby 3.3 or later. 16 | 17 | ## Quick start 18 | 19 | 1. Install VSCode [Ruby TypeProf](https://marketplace.visualstudio.com/items?itemName=mame.ruby-typeprof) extension: `code --install-extension mame.ruby-typeprof` 20 | 2. Run `typeprof --init` in your project root to create `typeprof.config.jsonc` file. 21 | Other options are available. See [typeprof.conf.jsonc](typeprof.conf.jsonc) for details. 22 | 23 | 3. Reopen your project in VSCode. 24 | 25 | ## Development 26 | 27 | 1. Git clone this repository: `git clone https://github.com/ruby/typeprof.git` 28 | 2. Install VSCode [Ruby TypeProf](https://marketplace.visualstudio.com/items?itemName=mame.ruby-typeprof) extension: `code --install-extension mame.ruby-typeprof` 29 | 3. Open the repository in VSCode: `code typeprof` 30 | 31 | ### Testing 32 | 33 | ```sh 34 | $ bundle install 35 | $ bundle exec rake test 36 | ``` 37 | 38 | ## More details 39 | 40 | https://speakerdeck.com/mame/good-first-issues-of-typeprof 41 | 42 | ## LICENSE 43 | 44 | See [LICENSE](LICENSE) file. -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | t.libs << "lib" 7 | t.test_files = FileList["test/**/*_test.rb"] 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /bin/typeprof: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../lib/typeprof" 4 | 5 | TypeProf::CLI::CLI.new(ARGV).run 6 | -------------------------------------------------------------------------------- /doc/doc.ja.md: -------------------------------------------------------------------------------- 1 | # TypeProf: 抽象解釈に基づくRubyの型解析器 2 | 3 | ## TypeProfの使い方 - CLIツールとして 4 | 5 | app.rb を解析する。 6 | 7 | ``` 8 | $ typeprof app.rb 9 | ``` 10 | 11 | 一部のメソッドの型を指定した sig/app.rbs とともに app.rb を解析する。 12 | 13 | ``` 14 | $ typeprof sig/app.rbs app.rb 15 | ``` 16 | 17 | 典型的な使用法は次の通り。 18 | 19 | ``` 20 | $ typeprof sig/app.rbs app.rb -o sig/app.gen.rbs 21 | ``` 22 | 23 | ## TypeProfの使い方 - Language Serverとして 24 | 25 | [RubyKaigi 2024の発表資料](https://speakerdeck.com/mame/good-first-issues-of-typeprof)を参照ください。 26 | 27 | ## TypeProfの解析方法 28 | 29 | TypeProfは、Rubyプログラムを型レベルで抽象的に実行するインタプリタです。 30 | 解析対象のプログラムを実行し、メソッドが受け取ったり返したりする型、インスタンス変数に代入される型を集めて出力します。 31 | すべての値はオブジェクトそのものではなく、原則としてオブジェクトの所属するクラスに抽象化されます(次節で詳説)。 32 | 33 | メソッドを呼び出す例を用いて説明します。 34 | 35 | ``` 36 | def foo(n) 37 | p n #=> Integer 38 | n.to_s 39 | end 40 | 41 | p foo(42) #=> String 42 | ``` 43 | 44 | TypeProfの解析結果は次の通り。 45 | 46 | ``` 47 | $ typeprof test.rb 48 | # Revealed types 49 | # test.rb:2 #=> Integer 50 | # test.rb:6 #=> String 51 | 52 | # Classes 53 | class Object 54 | def foo : (Integer) -> String 55 | end 56 | ``` 57 | 58 | `foo(42)`というメソッド呼び出しが実行されると、`Integer`オブジェクトの`42`ではなく、「`Integer`」という型(抽象値)が渡されます。 59 | メソッド`foo`は`n.to_s`が実行します。 60 | すると、組み込みメソッドの`Integer#to_s`が呼び出され、「String」という型が得られるので、メソッド`foo`はそれを返します。 61 | これらの実行結果の観察を集めて、TypeProfは「メソッド`foo`は`Integer`を受け取り、`String`を返す」という情報をRBSの形式で出力します。 62 | また、`p`の引数は`Revealed types`として出力されます。 63 | 64 | インスタンス変数は、通常のRubyではオブジェクトごとに記憶される変数ですが、TypeProfではクラス単位に集約されます。 65 | 66 | ``` 67 | class Foo 68 | def initialize 69 | @a = 42 70 | end 71 | 72 | attr_accessor :a 73 | end 74 | 75 | Foo.new.a = "str" 76 | 77 | p Foo.new.a #=> Integer | String 78 | ``` 79 | 80 | ``` 81 | $ typeprof test.rb 82 | # Revealed types 83 | # test.rb:11 #=> Integer | String 84 | 85 | # Classes 86 | class Foo 87 | attr_accessor a : Integer | String 88 | def initialize : -> Integer 89 | end 90 | ``` 91 | 92 | ## TypeProfの扱う抽象値 93 | 94 | 前述の通り、TypeProfはRubyの値を型のようなレベルに抽象化して扱います。 95 | ただし、クラスオブジェクトなど、一部の値は抽象化しません。 96 | 紛らわしいので、TypeProfが使う抽象化された値のことを「抽象値」と呼びます。 97 | 98 | TypeProfが扱う抽象値は次のとおりです。 99 | 100 | * クラスのインスタンス 101 | * クラスオブジェクト 102 | * シンボル 103 | * `untyped` 104 | * 抽象値のユニオン 105 | * コンテナクラスのインスタンス 106 | * Procオブジェクト 107 | 108 | クラスのインスタンスはもっとも普通の値です。 109 | `Foo.new`というRubyコードが返す抽象値は、クラス`Foo`のインスタンスで、少し紛らわしいですがこれはRBS出力の中で`Foo`と表現されます。 110 | `42`という整数リテラルは`Integer`のインスタンス、`"str"`という文字列リテラルは`String`のインスタンスになります。 111 | 112 | クラスオブジェクトは、クラスそのものを表す値で、たとえば定数`Integer`や`String`に入っているオブジェクトです。 113 | このオブジェクトは厳密にはクラス`Class`のインスタンスですが、`Class`に抽象化はされません。 114 | 抽象化してしまうと、定数の参照やクラスメソッドが使えなくなるためです。 115 | 116 | シンボルは、`:foo`のようなSymbolリテラルが返す値です。 117 | シンボルは、キーワード引数、JSONデータのキー、`Module#attr_reader`の引数など、具体的な値が必要になることが多いので、抽象化されません。 118 | ただし、`String#to_sym`で生成されるSymbolや、式展開を含むSymbolリテラル(`:"foo_#{ x }"`など)はクラス`Symbol`のインスタンスとして扱われます。 119 | 120 | `untyped`は、解析の限界や制限などによって追跡ができない場合に生成される抽象値です。 121 | `untyped`に対する演算やメソッド呼び出しは無視され、評価結果は`untyped`となります。 122 | 123 | 抽象値のユニオンは、抽象値に複数の可能性があることを表現する値です。 124 | 人工的ですが、`rand < 0.5 ? 42 : "str"`の結果は`Integer | String`という抽象値になります。 125 | 126 | コンテナクラスのインスタンスは、ArrayやHashのように他の抽象値を要素とするオブジェクトです。 127 | いまのところ、ArrayとEnumeratorとHashのみ対応しています。 128 | 詳細は後述します。 129 | 130 | Procオブジェクトは、ラムダ式(`-> { ... }`)やブロック仮引数(`&blk`)で作られるクロージャです。 131 | これらは抽象化されず、コード片と結びついた具体的な値として扱われます。 132 | これらに渡された引数や返された値によってRBS出力されます。 133 | 134 | TODO: write more -------------------------------------------------------------------------------- /lib/typeprof.rb: -------------------------------------------------------------------------------- 1 | require_relative "typeprof/version" 2 | require_relative "typeprof/code_range" 3 | require_relative "typeprof/diagnostic" 4 | require_relative "typeprof/core" 5 | require_relative "typeprof/lsp" 6 | require_relative "typeprof/cli" 7 | -------------------------------------------------------------------------------- /lib/typeprof/cli.rb: -------------------------------------------------------------------------------- 1 | require "optparse" 2 | require "pathname" 3 | require "io/console" 4 | 5 | require_relative "cli/cli" 6 | -------------------------------------------------------------------------------- /lib/typeprof/cli/typeprof.conf.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "typeprof_version": "experimental", 3 | "rbs_dir": "sig/" 4 | // "analysis_unit_dirs": [], 5 | // "diagnostic_severity": "warning" 6 | } 7 | -------------------------------------------------------------------------------- /lib/typeprof/code_range.rb: -------------------------------------------------------------------------------- 1 | module TypeProf 2 | class CodePosition 3 | def initialize(lineno, column) 4 | @lineno = lineno 5 | @column = column 6 | end 7 | 8 | def self.from_lsp(pos) 9 | new(pos[:line] + 1, pos[:character]) 10 | end 11 | 12 | def to_lsp 13 | { line: @lineno - 1, character: @column } 14 | end 15 | 16 | attr_reader :lineno, :column 17 | 18 | def <=>(other) 19 | cmp = @lineno <=> other.lineno 20 | cmp == 0 ? @column <=> other.column : cmp 21 | end 22 | 23 | include Comparable 24 | 25 | def ==(other) 26 | @lineno == other.lineno && @column == other.column 27 | end 28 | 29 | alias eql? == 30 | 31 | def hash 32 | [@lineno, @column].hash 33 | end 34 | 35 | def to_s 36 | "(%d,%d)" % [@lineno, @column] 37 | end 38 | 39 | alias inspect to_s 40 | 41 | def left 42 | raise if @column == 0 43 | CodePosition.new(@lineno, @column - 1) 44 | end 45 | 46 | def right 47 | CodePosition.new(@lineno, @column + 1) 48 | end 49 | end 50 | 51 | class CodeRange 52 | def initialize(first, last) 53 | @first = first 54 | @last = last 55 | raise unless first 56 | end 57 | 58 | def self.from_node(node, encoding = Encoding::UTF_16LE) 59 | node = node.location if node.respond_to?(:location) 60 | if node.is_a?(Prism::Location) 61 | pos1 = CodePosition.new(node.start_line, node.start_code_units_column(encoding)) 62 | pos2 = CodePosition.new(node.end_line, node.end_code_units_column(encoding)) 63 | elsif node.is_a?(RBS::Location) 64 | pos1 = CodePosition.new(*node.start_loc) 65 | pos2 = CodePosition.new(*node.end_loc) 66 | else 67 | p node.class.ancestors 68 | raise "unknown type: #{ node.class }" 69 | end 70 | new(pos1, pos2) 71 | end 72 | 73 | def self.[](a, b, c, d) 74 | pos1 = CodePosition.new(a, b) 75 | pos2 = CodePosition.new(c, d) 76 | new(pos1, pos2) 77 | end 78 | 79 | def to_lsp 80 | { start: @first.to_lsp, end: @last.to_lsp } 81 | end 82 | 83 | attr_reader :first, :last 84 | 85 | def include?(pos) 86 | @first <= pos && pos < @last 87 | end 88 | 89 | def ==(other) 90 | @first == other.first && @last == other.last 91 | end 92 | 93 | alias eql? == 94 | 95 | def hash 96 | [@first, @last].hash 97 | end 98 | 99 | def to_s 100 | "%p-%p" % [@first, @last] 101 | end 102 | 103 | alias inspect to_s 104 | 105 | def ==(other) 106 | @first == other.first && @last == other.last 107 | end 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /lib/typeprof/core.rb: -------------------------------------------------------------------------------- 1 | require "rbs" 2 | require "prism" 3 | require_relative "core/util" 4 | require_relative "core/ast" 5 | require_relative "core/ast/base" 6 | require_relative "core/ast/module" 7 | require_relative "core/ast/method" 8 | require_relative "core/ast/call" 9 | require_relative "core/ast/control" 10 | require_relative "core/ast/const" 11 | require_relative "core/ast/variable" 12 | require_relative "core/ast/value" 13 | require_relative "core/ast/misc" 14 | require_relative "core/ast/meta" 15 | require_relative "core/ast/pattern" 16 | require_relative "core/ast/sig_decl" 17 | require_relative "core/ast/sig_type" 18 | require_relative "core/type" 19 | require_relative "core/env" 20 | require_relative "core/env/method_entity" 21 | require_relative "core/env/module_entity" 22 | require_relative "core/env/type_alias_entity" 23 | require_relative "core/env/value_entity" 24 | require_relative "core/env/method" 25 | require_relative "core/env/static_read" 26 | require_relative "core/graph/change_set" 27 | require_relative "core/graph/vertex" 28 | require_relative "core/graph/filter" 29 | require_relative "core/graph/box" 30 | require_relative "core/builtin" 31 | require_relative "core/service" 32 | -------------------------------------------------------------------------------- /lib/typeprof/core/env/method_entity.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::Core 2 | class MethodEntity 3 | def initialize 4 | @builtin = nil 5 | @decls = Set[] 6 | @defs = Set[] 7 | @aliases = {} 8 | @method_call_boxes = Set[] 9 | end 10 | 11 | attr_reader :decls, :defs, :aliases, :method_call_boxes 12 | attr_accessor :builtin 13 | 14 | def add_decl(decl) 15 | @decls << decl 16 | end 17 | 18 | def remove_decl(decl) 19 | @decls.delete(decl) || raise 20 | end 21 | 22 | def add_def(mdef) 23 | @defs << mdef 24 | self 25 | end 26 | 27 | def remove_def(mdef) 28 | @defs.delete(mdef) || raise 29 | end 30 | 31 | def add_alias(node, old_mid) 32 | @aliases[node] = old_mid 33 | end 34 | 35 | def remove_alias(node) 36 | @aliases.delete(node) || raise 37 | end 38 | 39 | def exist? 40 | @builtin || !@decls.empty? || !@defs.empty? 41 | end 42 | 43 | def add_run_all_mdefs(genv) 44 | @defs.each do |mdef| 45 | genv.add_run(mdef) 46 | end 47 | end 48 | 49 | def add_run_all_method_call_boxes(genv) 50 | @method_call_boxes.each do |box| 51 | genv.add_run(box) 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/typeprof/core/env/static_read.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::Core 2 | class StaticRead 3 | def initialize(name) 4 | @name = name 5 | @followers = Set[] 6 | @source_modules = Set[] 7 | end 8 | 9 | attr_reader :name, :followers 10 | 11 | def propagate(genv) 12 | @followers.each do |follower| 13 | case follower 14 | when ModuleEntity 15 | genv.add_static_eval_queue(:parent_modules_changed, follower) 16 | when ScopedStaticRead 17 | follower.on_cbase_updated(genv) 18 | when Box, IsAFilter 19 | genv.add_run(follower) 20 | else 21 | raise follower.inspect 22 | end 23 | end 24 | end 25 | 26 | def destroy(genv) 27 | @source_modules.each do |mod| 28 | mod.static_reads[@name].delete(self) || raise 29 | end 30 | @source_modules.clear 31 | end 32 | 33 | def resolve(genv, cref, search_ancestors, break_object) 34 | destroy(genv) 35 | 36 | while cref 37 | scope = cref.cpath 38 | mod = genv.resolve_cpath(scope) 39 | genv.each_superclass(mod, false) do |mod, _singleton| 40 | break if mod == genv.mod_object && break_object 41 | 42 | unless @source_modules.include?(mod) 43 | @source_modules << mod 44 | (mod.static_reads[@name] ||= Set[]) << self 45 | end 46 | 47 | return if check_module(genv, mod) 48 | 49 | break unless search_ancestors 50 | end 51 | search_ancestors = false 52 | cref = cref.outer 53 | end 54 | resolution_failed(genv) 55 | end 56 | end 57 | 58 | class BaseStaticRead < StaticRead 59 | def initialize(genv, name, cref, strict_const_scope) 60 | super(name) 61 | @cref = cref 62 | @search_ancestors = !strict_const_scope 63 | genv.add_static_eval_queue(:static_read_changed, self) 64 | end 65 | 66 | attr_reader :cref 67 | 68 | def on_scope_updated(genv) 69 | resolve(genv, @cref, @search_ancestors, false) 70 | end 71 | end 72 | 73 | class ScopedStaticRead < StaticRead 74 | def initialize(name, cbase, strict_const_scope) 75 | super(name) 76 | @cbase = cbase 77 | @cbase.followers << self if @cbase 78 | @search_ancestors = !strict_const_scope 79 | end 80 | 81 | def on_cbase_updated(genv) 82 | if @cbase && @cbase.cpath 83 | resolve(genv, CRef.new(@cbase.cpath, :class, nil, nil), @search_ancestors, true) 84 | else 85 | resolution_failed(genv) 86 | end 87 | end 88 | end 89 | 90 | module ConstRead 91 | def check_module(genv, mod) 92 | cdef = mod.consts[@name] 93 | if cdef && cdef.exist? 94 | inner_mod = genv.resolve_cpath(mod.cpath + [@name]) # TODO 95 | cpath = inner_mod.exist? ? inner_mod.cpath : nil 96 | update_module(genv, cpath, cdef) 97 | return true 98 | end 99 | return false 100 | end 101 | 102 | def resolution_failed(genv) 103 | update_module(genv, nil, nil) 104 | end 105 | 106 | def update_module(genv, cpath, cdef) 107 | if cpath != @cpath || cdef != @cdef 108 | @cpath = cpath 109 | @cdef = cdef 110 | propagate(genv) 111 | end 112 | end 113 | 114 | attr_reader :cpath, :cdef 115 | end 116 | 117 | class BaseConstRead < BaseStaticRead 118 | include ConstRead 119 | end 120 | 121 | class ScopedConstRead < ScopedStaticRead 122 | include ConstRead 123 | end 124 | 125 | module TypeAliasRead 126 | def check_module(genv, mod) 127 | tae = mod.type_aliases[@name] 128 | if tae && tae.exist? 129 | update_type_alias(genv, tae) 130 | return true 131 | end 132 | return false 133 | end 134 | 135 | def resolution_failed(genv) 136 | update_type_alias(genv, nil) 137 | end 138 | 139 | def update_type_alias(genv, tae) 140 | if tae != @type_alias_entity 141 | @type_alias_entity = tae 142 | propagate(genv) 143 | end 144 | end 145 | 146 | attr_reader :type_alias_entity 147 | end 148 | 149 | class BaseTypeAliasRead < BaseStaticRead 150 | include TypeAliasRead 151 | end 152 | 153 | class ScopedTypeAliasRead < ScopedStaticRead 154 | include TypeAliasRead 155 | end 156 | end 157 | -------------------------------------------------------------------------------- /lib/typeprof/core/env/type_alias_entity.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::Core 2 | class TypeAliasEntity 3 | def initialize 4 | @decls = Set[] 5 | @type = nil 6 | end 7 | 8 | attr_reader :decls, :type 9 | 10 | def exist? 11 | !@decls.empty? 12 | end 13 | 14 | def add_decl(decl) 15 | @decls << decl 16 | @type = decl.type unless @type 17 | # TODO: report an error if there are duplicated declarations 18 | end 19 | 20 | def remove_decl(decl) 21 | @decls.delete(decl) || raise 22 | if @type == decl.type 23 | @type = @decls.empty? ? nil : @decls.to_a.first.type 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/typeprof/core/env/value_entity.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::Core 2 | class ValueEntity 3 | def initialize 4 | @decls = Set[] 5 | @defs = Set[] 6 | @read_boxes = Set[] 7 | @vtx = Vertex.new(self) 8 | end 9 | 10 | attr_reader :decls, :defs, :read_boxes, :vtx 11 | 12 | def add_decl(decl) 13 | @decls << decl 14 | end 15 | 16 | def remove_decl(decl) 17 | @decls.delete(decl) || raise 18 | end 19 | 20 | def add_def(def_) 21 | @defs << def_ 22 | end 23 | 24 | def remove_def(def_) 25 | @defs.delete(def_) || raise 26 | end 27 | 28 | def exist? 29 | !@decls.empty? || !@defs.empty? 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/typeprof/core/util.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::Core 2 | class Set 3 | def self.[](*elems) 4 | h = Hash.new(false) 5 | elems.each {|elem| h[elem] = true } 6 | new(h) 7 | end 8 | 9 | def initialize(hash) 10 | @hash = hash 11 | end 12 | 13 | def internal_hash = @hash 14 | 15 | def dup 16 | Set.new(@hash.dup) 17 | end 18 | 19 | def <<(elem) 20 | raise if @hash.include?(elem) 21 | @hash[elem] = true 22 | self 23 | end 24 | 25 | def include?(elem) 26 | @hash[elem] 27 | end 28 | 29 | def merge(set) 30 | raise NotImplementedError 31 | end 32 | 33 | def each(&blk) 34 | @hash.each_key(&blk) 35 | end 36 | 37 | def empty? 38 | @hash.empty? 39 | end 40 | 41 | def delete(elem) 42 | raise unless @hash.include?(elem) 43 | @hash.delete(elem) 44 | end 45 | 46 | def clear 47 | @hash.clear 48 | end 49 | 50 | def to_a 51 | @hash.keys 52 | end 53 | 54 | def size 55 | @hash.size 56 | end 57 | 58 | def -(other) 59 | h = @hash.dup 60 | other.each do |elem| 61 | h.delete(elem) 62 | end 63 | Set.new(h) 64 | end 65 | 66 | def pretty_print(q) 67 | q.text "Set[" 68 | q.group do 69 | q.nest(1) do 70 | @hash.each_key do |elem| 71 | q.breakable "" 72 | q.pp elem 73 | q.text "," 74 | end 75 | end 76 | q.breakable "" 77 | end 78 | q.text "]" 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/typeprof/diagnostic.rb: -------------------------------------------------------------------------------- 1 | module TypeProf 2 | class Diagnostic 3 | def initialize(node, meth, msg, tags: nil) 4 | @node = node 5 | @meth = meth 6 | @msg = msg 7 | @tags = tags 8 | end 9 | 10 | def reuse(new_node) 11 | @node = new_node 12 | end 13 | 14 | attr_reader :msg, :tags 15 | 16 | def code_range 17 | @node.send(@meth) 18 | end 19 | 20 | SEVERITY = { error: 1, warning: 2, info: 3, hint: 4 } 21 | TAG = { unnecessary: 1, deprecated: 2 } 22 | 23 | def to_lsp(severity: :error) 24 | json = { 25 | range: code_range.to_lsp, 26 | source: "TypeProf", 27 | message: @msg, 28 | } 29 | json[:severity] = SEVERITY[severity] 30 | json[:tags] = @tags.map {|tag| TAG[tag] } if @tags 31 | json 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/typeprof/lsp.rb: -------------------------------------------------------------------------------- 1 | require "socket" 2 | require "json" 3 | 4 | require_relative "lsp/text" 5 | require_relative "lsp/messages" 6 | require_relative "lsp/server" 7 | require_relative "lsp/util" 8 | -------------------------------------------------------------------------------- /lib/typeprof/lsp/text.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::LSP 2 | class Text 3 | #: (String, String, Integer) -> void 4 | def initialize(path, text, version) 5 | @path = path 6 | @lines = Text.split(text) 7 | @version = version 8 | end 9 | 10 | attr_reader :path, :lines, :version 11 | 12 | def self.split(str) 13 | lines = str.lines 14 | lines << "" if lines.empty? || lines.last.include?("\n") 15 | lines 16 | end 17 | 18 | def string 19 | @lines.join 20 | end 21 | 22 | def apply_changes(changes, version) 23 | changes.each do |change| 24 | change => { 25 | range: { 26 | start: { line: start_row, character: start_col }, 27 | end: { line: end_row , character: end_col } 28 | }, 29 | text: new_text, 30 | } 31 | 32 | new_text = Text.split(new_text) 33 | 34 | prefix = @lines[start_row][0...start_col] 35 | suffix = @lines[end_row][end_col...] 36 | if new_text.size == 1 37 | new_text[0] = prefix + new_text[0] + suffix 38 | else 39 | new_text[0] = prefix + new_text[0] 40 | new_text[-1] = new_text[-1] + suffix 41 | end 42 | @lines[start_row .. end_row] = new_text 43 | end 44 | 45 | validate 46 | 47 | @version = version 48 | end 49 | 50 | def validate 51 | raise unless @lines[0..-2].all? {|s| s.count("\n") == 1 && s.end_with?("\n") } 52 | raise unless @lines[-1].count("\n") == 0 53 | end 54 | 55 | def modify_for_completion(changes, pos) 56 | pos => { line: row, character: col } 57 | if col >= 2 && @lines[row][col - 1] == "." && (col == 1 || @lines[row][col - 2] != ".") 58 | @lines[row][col - 1] = " " 59 | yield string, ".", { line: row, character: col - 2} 60 | @lines[row][col - 1] = "." 61 | elsif col >= 3 && @lines[row][col - 2, 2] == "::" 62 | @lines[row][col - 2, 2] = " " 63 | yield string, "::", { line: row, character: col - 3 } 64 | @lines[row][col - 2, 2] = "::" 65 | else 66 | yield string, nil, { line: row, character: col } 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/typeprof/lsp/util.rb: -------------------------------------------------------------------------------- 1 | module TypeProf::LSP 2 | def self.load_json_with_comments(path, **opts) 3 | json = File.read(path) 4 | 5 | state = :normal 6 | last_comma_index = nil 7 | trailing_commas = [] 8 | json = json.gsub(%r(\\.|//|/\*|\*/|[",\n/}\]*]|(\s+)|[^\s\\"*/,]+)) do 9 | case $& 10 | when "//" 11 | state = :single_line_comment if state == :normal 12 | when "\n" 13 | state = :normal if state == :single_line_comment 14 | next "\n" 15 | when "/*" 16 | state = :multi_line_comment if state == :normal 17 | when "*/" 18 | state = :normal if state == :multi_line_comment 19 | next " " if state == :normal 20 | when "\"" 21 | case state 22 | when :normal 23 | last_comma_index = nil 24 | state = :string_literal 25 | when :string_literal 26 | state = :normal 27 | end 28 | when "," 29 | last_comma_index = $~.begin(0) if state == :normal 30 | when "}", "]" 31 | if state == :normal && last_comma_index 32 | trailing_commas << last_comma_index 33 | last_comma_index = nil 34 | end 35 | when $1 36 | else 37 | last_comma_index = nil if state == :normal 38 | end 39 | if state == :normal || state == :string_literal 40 | $& 41 | else 42 | " " * $&.size 43 | end 44 | end 45 | trailing_commas.each do |i| 46 | json[i] = " " 47 | end 48 | 49 | JSON.parse(json, **opts) 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/typeprof/version.rb: -------------------------------------------------------------------------------- 1 | module TypeProf 2 | VERSION = "0.30.1" 3 | end 4 | -------------------------------------------------------------------------------- /scenario/args/forwarding_arguments.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(...) 3 | nil 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: (*untyped, **untyped) -> nil 9 | end 10 | 11 | ## update 12 | def foo(a, ...) 13 | a 14 | end 15 | 16 | foo(1) 17 | 18 | ## assert 19 | class Object 20 | def foo: (Integer, *untyped, **untyped) -> Integer 21 | end 22 | -------------------------------------------------------------------------------- /scenario/args/keyword-twice.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def initialize(k:) 4 | end 5 | end 6 | 7 | class Bar < Foo 8 | end 9 | 10 | obj = rand < 0.5 ? Foo : Bar 11 | obj.new(k: 1) 12 | 13 | ## assert 14 | class Foo 15 | def initialize: (k: Integer) -> nil 16 | end 17 | class Bar < Foo 18 | end 19 | 20 | ## update 21 | class Foo 22 | def initialize(k: :default) 23 | end 24 | end 25 | 26 | class Bar < Foo 27 | end 28 | 29 | obj = rand < 0.5 ? Foo : Bar 30 | obj.new(k: 1) 31 | 32 | ## assert 33 | class Foo 34 | def initialize: (?k: :default | Integer) -> nil 35 | end 36 | class Bar < Foo 37 | end 38 | -------------------------------------------------------------------------------- /scenario/args/keyword_splat.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(check: false) 3 | end 4 | 5 | opt = { foo: 1 } 6 | foo(**opt) # I am not sure what is the best here, but tentatively... 7 | 8 | ## assert 9 | class Object 10 | def foo: (?check: Integer | false) -> nil 11 | end 12 | -------------------------------------------------------------------------------- /scenario/args/no-keyword.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check(**nil) 3 | end 4 | 5 | ## assert 6 | class Object 7 | def check: -> nil 8 | end 9 | -------------------------------------------------------------------------------- /scenario/args/positionals_rb_to_rb1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(a, b, o1 = 1, o2 = o1) 3 | end 4 | 5 | foo(:A, :B, :O1) 6 | 7 | ## assert 8 | class Object 9 | def foo: (:A, :B, ?:O1 | Integer, ?:O1 | Integer) -> nil 10 | end 11 | 12 | ## update 13 | def foo(a, b, o1 = 1, o2 = o1, x, y) 14 | end 15 | 16 | foo(:A, :B, :O1, :X, :Y) 17 | 18 | ## assert 19 | class Object 20 | def foo: (:A, :B, ?:O1 | Integer, ?:O1 | Integer, :X, :Y) -> nil 21 | end 22 | 23 | ## update 24 | def foo(a, b, *r) 25 | end 26 | 27 | foo(:A, :B, :R1, :R2, :R3) 28 | 29 | ## assert 30 | class Object 31 | def foo: (:A, :B, *:R1 | :R2 | :R3) -> nil 32 | end 33 | 34 | ## update 35 | def foo(a, b, *r, x, y) 36 | end 37 | 38 | foo(:A, :B, :R1, :R2, :R3, :X, :Y) 39 | 40 | ## assert 41 | class Object 42 | def foo: (:A, :B, *:R1 | :R2 | :R3, :X, :Y) -> nil 43 | end 44 | 45 | ## update 46 | def foo(a, b, o1 = 1, o2 = o1, *r, x, y) 47 | end 48 | 49 | foo(:A, :B, :O1, :O2, :R1, :R2, :R3, :X, :Y) 50 | 51 | ## assert 52 | class Object 53 | def foo: (:A, :B, ?:O1 | Integer, ?:O1 | :O2 | Integer, *:R1 | :R2 | :R3, :X, :Y) -> nil 54 | end 55 | -------------------------------------------------------------------------------- /scenario/args/positionals_rb_to_rb2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(a, b, o1 = 1, o2 = o1) 3 | end 4 | 5 | ary = ["str"].to_a 6 | foo(:A, *ary) 7 | 8 | ## assert 9 | class Object 10 | def foo: (:A, String, ?Integer | String, ?Integer | String) -> nil 11 | end 12 | 13 | ## update 14 | def foo(a, b, o1 = 1, o2 = o1) 15 | end 16 | 17 | ary = ["str"].to_a 18 | foo(:A, :B, :C, *ary) 19 | 20 | ## assert 21 | class Object 22 | def foo: (:A, :B, ?:C | Integer, ?:C | Integer | String) -> nil 23 | end 24 | 25 | ## update 26 | def foo(a, b, o1 = 1, o2 = o1) 27 | end 28 | 29 | ary = ["str"].to_a 30 | foo(:A, :B, :C, *ary) 31 | 32 | ## assert 33 | class Object 34 | def foo: (:A, :B, ?:C | Integer, ?:C | Integer | String) -> nil 35 | end 36 | 37 | ## update 38 | def foo(o1 = 1, o2 = o1, y, z) 39 | end 40 | 41 | ary = ["str"].to_a 42 | foo(*ary, :Z) 43 | 44 | ## assert 45 | class Object 46 | def foo: (?Integer | String, ?Integer | String, String, :Z) -> nil 47 | end 48 | 49 | ## update 50 | def foo(o1 = 1, o2 = o1, y, z) 51 | end 52 | 53 | ary = ["str"].to_a 54 | foo(*ary, :X, :Y, :Z) 55 | 56 | ## assert 57 | class Object 58 | def foo: (?:X | Integer | String, ?:X | Integer | String, :Y, :Z) -> nil 59 | end 60 | -------------------------------------------------------------------------------- /scenario/args/positionals_rb_to_rb3.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(a, b, *r) 3 | end 4 | 5 | ary = ["str"].to_a 6 | foo(:A, *ary) 7 | 8 | ## assert 9 | class Object 10 | def foo: (:A, String, *String) -> nil 11 | end 12 | 13 | ## update 14 | def foo(a, b, *r) 15 | end 16 | 17 | ary = ["str"].to_a 18 | foo(:A, :B, :C, *ary) 19 | 20 | ## assert 21 | class Object 22 | def foo: (:A, :B, *:C | String) -> nil 23 | end 24 | 25 | ## update 26 | def foo(a, b, o1 = 1, o2 = o1, *r) 27 | end 28 | 29 | ary = ["str"].to_a 30 | foo(:A, :B, :C, :D, :E, *ary) 31 | 32 | ## assert 33 | class Object 34 | def foo: (:A, :B, ?:C | Integer, ?:C | :D | Integer, *:E | String) -> nil 35 | end 36 | 37 | ## update 38 | def foo(*r, y, z) 39 | end 40 | 41 | ary = ["str"].to_a 42 | foo(*ary, :Z) 43 | 44 | ## assert 45 | class Object 46 | def foo: (*String, String, :Z) -> nil 47 | end 48 | 49 | ## update 50 | def foo(*r, y, z) 51 | end 52 | 53 | ary = ["str"].to_a 54 | foo(*ary, :X, :Y, :Z) 55 | 56 | ## assert 57 | class Object 58 | def foo: (*:X | String, :Y, :Z) -> nil 59 | end 60 | 61 | ## update 62 | def foo(a, b, *r, y, z) 63 | end 64 | 65 | ary = ["str"].to_a 66 | foo(*ary, :X, :Y, :Z) 67 | 68 | ## assert 69 | class Object 70 | def foo: (:X | String, :X | String, *:X | String, :Y, :Z) -> nil 71 | end 72 | -------------------------------------------------------------------------------- /scenario/args/positionals_rb_to_rb_block.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def initialize(n) 4 | yield "string", 1.0 5 | nil 6 | end 7 | end 8 | 9 | Foo.new(1) do |x| 10 | 1 11 | end 12 | 13 | Foo.new(1) do |x, y| 14 | "str" 15 | end 16 | 17 | ## assert 18 | class Foo 19 | def initialize: (Integer) { (String, Float) -> (Integer | String) } -> nil 20 | end 21 | -------------------------------------------------------------------------------- /scenario/args/positionals_rb_to_rbs.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: (String, *Integer) -> :ok 4 | end 5 | 6 | ## update: test.rb 7 | def test_ok1 8 | foo("str") 9 | end 10 | def test_ok2 11 | foo("str", 1) 12 | end 13 | def test_ok3 14 | foo("str", 1, 2, 3) 15 | end 16 | def test_ok4 17 | ary = [1].to_a 18 | foo("str", *ary) 19 | end 20 | def test_ok5 21 | foo("str", *$untyped, 1, *$untyped, 2) 22 | end 23 | def test_ng1 24 | foo("str", "str") 25 | end 26 | def test_ng2 27 | foo("str", 1, 2, 3, "str") 28 | end 29 | def test_ng3 30 | foo("str", *$untyped, "str") 31 | end 32 | 33 | ## assert 34 | class Object 35 | def test_ok1: -> :ok 36 | def test_ok2: -> :ok 37 | def test_ok3: -> :ok 38 | def test_ok4: -> :ok 39 | def test_ok5: -> :ok 40 | def test_ng1: -> :ok 41 | def test_ng2: -> :ok 42 | def test_ng3: -> :ok 43 | end 44 | 45 | ## diagnostics 46 | (18,2)-(18,5): wrong type of arguments 47 | (21,2)-(21,5): wrong type of arguments 48 | (24,2)-(24,5): wrong type of arguments 49 | 50 | ## update: test.rbs 51 | class Object 52 | def foo: (String, ?Integer) -> :ok 53 | end 54 | 55 | ## update: test.rb 56 | def test_ok1 57 | foo("str") 58 | end 59 | def test_ok2 60 | foo("str", 1) 61 | end 62 | def test_ng1 63 | foo("str", 1, 2) 64 | end 65 | def test_ng2 66 | ary = [1].to_a 67 | foo("str", *ary) 68 | end 69 | 70 | ## assert 71 | class Object 72 | def test_ok1: -> :ok 73 | def test_ok2: -> :ok 74 | def test_ng1: -> :ok 75 | def test_ng2: -> :ok 76 | end 77 | 78 | ## diagnostics 79 | (8,2)-(8,5): wrong type of arguments 80 | (12,2)-(12,5): wrong type of arguments 81 | 82 | ## update: test.rbs 83 | class Object 84 | def foo: (String, ?Float, *Integer) -> :ok 85 | end 86 | 87 | ## update: test.rb 88 | def test_ok1 89 | foo("str") 90 | end 91 | def test_ok2 92 | foo("str", 1.0) 93 | end 94 | def test_ok3 95 | foo("str", 1.0, 1, 2, 3) 96 | end 97 | def test_ok4 98 | ary = [1].to_a 99 | foo("str", 1.0, *ary, 2, *ary, 3) 100 | end 101 | def test_ng1 102 | foo("str", 1) 103 | end 104 | def test_ng2 105 | foo("str", 1, 2, 3) 106 | end 107 | def test_ng3 108 | ary = [1].to_a 109 | foo("str", *ary) 110 | end 111 | def test_ng4 112 | ary = [1].to_a 113 | foo(*ary) 114 | end 115 | 116 | ## assert 117 | class Object 118 | def test_ok1: -> :ok 119 | def test_ok2: -> :ok 120 | def test_ok3: -> :ok 121 | def test_ok4: -> :ok 122 | def test_ng1: -> :ok 123 | def test_ng2: -> :ok 124 | def test_ng3: -> :ok 125 | def test_ng4: -> :ok 126 | end 127 | 128 | ## diagnostics 129 | (15,2)-(15,5): wrong type of arguments 130 | (18,2)-(18,5): wrong type of arguments 131 | (22,2)-(22,5): wrong type of arguments 132 | (26,2)-(26,5): wrong type of arguments 133 | 134 | ## update: test.rbs 135 | class Object 136 | def foo: (String, ?Float, *(Float | Integer)) -> :ok 137 | end 138 | 139 | ## update: test.rb 140 | def test_ok1 141 | ary = [1.0].to_a 142 | foo("str", *ary, 1.0) 143 | end 144 | def test_ok2 145 | ary = [1].to_a 146 | foo("str", 1.0, *ary) 147 | end 148 | def test_ng1 149 | ary = [1].to_a 150 | foo("str", *ary, 1) 151 | end 152 | 153 | ## assert 154 | class Object 155 | def test_ok1: -> :ok 156 | def test_ok2: -> :ok 157 | def test_ng1: -> :ok 158 | end 159 | 160 | ## diagnostics 161 | (11,2)-(11,5): wrong type of arguments 162 | -------------------------------------------------------------------------------- /scenario/args/positionals_rbs_to_rb.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | #: (*Integer) -> Integer 3 | def foo(x, y) 4 | x + y 5 | end 6 | 7 | ## assert 8 | class Object 9 | def foo: (Integer, Integer) -> Integer 10 | end 11 | 12 | ## update 13 | #: (*Integer) -> String 14 | def foo(x, y) 15 | x + y 16 | end 17 | 18 | ## diagnostics 19 | (3,2)-(3,7): expected: String; actual: Integer 20 | -------------------------------------------------------------------------------- /scenario/args/positionals_rbs_to_rb_block.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&b) 3 | 1.times(&b) 4 | end 5 | 6 | # TODO: Object means "void" 7 | 8 | ## assert 9 | class Object 10 | def foo: { (Integer) -> Object } -> Integer 11 | end 12 | -------------------------------------------------------------------------------- /scenario/args/splat-twice.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def gen 4 | [1] 5 | end 6 | 7 | def check 8 | ary = [] 9 | ary.append(*gen) 10 | ary.append(*gen) 11 | end 12 | end 13 | 14 | ## assert 15 | class Foo 16 | def gen: -> [Integer] 17 | def check: -> Array[Integer] 18 | end 19 | -------------------------------------------------------------------------------- /scenario/args/splat_rb_to_rb.rb: -------------------------------------------------------------------------------- 1 | ## update: base.rb 2 | def foo 3 | yield [42, "str"] 4 | end 5 | 6 | ## update: test.rb 7 | def test_first 8 | foo do |n, _s| 9 | return n 10 | end 11 | nil 12 | end 13 | 14 | def test_second 15 | foo do |_n, s| 16 | return s 17 | end 18 | nil 19 | end 20 | 21 | ## assert 22 | class Object 23 | def test_first: -> Integer? 24 | def test_second: -> String? 25 | end 26 | -------------------------------------------------------------------------------- /scenario/args/splat_rbs_to_rb.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: { ([Integer, String]) -> void } -> void 4 | end 5 | 6 | ## update: test.rb 7 | def test_first 8 | foo do |n, _s| 9 | return n 10 | end 11 | nil 12 | end 13 | 14 | def test_second 15 | foo do |_n, s| 16 | return s 17 | end 18 | nil 19 | end 20 | 21 | ## assert 22 | class Object 23 | def test_first: -> Integer? 24 | def test_second: -> String? 25 | end 26 | -------------------------------------------------------------------------------- /scenario/array/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | def foo(a) 3 | a 4 | end 5 | 6 | ## update: test1.rb 7 | foo([1, 2, 3].to_a) 8 | 9 | ## assert: test0.rb 10 | class Object 11 | def foo: (Array[Integer]) -> Array[Integer] 12 | end 13 | 14 | ## update: test1.rb 15 | foo([1, 2, 3].to_a) 16 | foo(["str"].to_a) 17 | 18 | ## assert: test0.rb 19 | class Object 20 | def foo: (Array[Integer] | Array[String]) -> (Array[Integer] | Array[String]) 21 | end 22 | 23 | ## update: test1.rb 24 | foo(["str"].to_a) 25 | 26 | ## assert: test0.rb 27 | class Object 28 | def foo: (Array[String]) -> Array[String] 29 | end 30 | -------------------------------------------------------------------------------- /scenario/array/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | def bar(a) 3 | [a].to_a 4 | end 5 | 6 | ## update: test1.rb 7 | bar(1) 8 | 9 | ## assert: test0.rb 10 | class Object 11 | def bar: (Integer) -> Array[Integer] 12 | end 13 | 14 | ## update: test1.rb 15 | bar(1) 16 | bar("str") 17 | 18 | ## assert: test0.rb 19 | class Object 20 | def bar: (Integer | String) -> Array[Integer | String] 21 | end 22 | 23 | ## update: test1.rb 24 | bar("str") 25 | 26 | ## assert: test0.rb 27 | class Object 28 | def bar: (String) -> Array[String] 29 | end 30 | -------------------------------------------------------------------------------- /scenario/array/push.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | if rand < 0.5 4 | a = [].map {|arg| 1 } 5 | else 6 | a = [] 7 | end 8 | a << :foo 9 | end 10 | 11 | ## assert 12 | class Object 13 | def check: -> (Array[Integer] | []) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/array/rbs_tuple.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | { 4 | a: 1, 5 | b: "str", 6 | }.to_a 7 | end 8 | 9 | def bar 10 | [1, 2, 3].minmax 11 | end 12 | 13 | def baz 14 | ret = nil 15 | %w(foo bar baz).each_with_index do |x, i| 16 | ret = i 17 | end 18 | ret 19 | end 20 | 21 | ## assert 22 | class Object 23 | def foo: -> Array[[:a | :b, Integer | String]] 24 | def bar: -> [Integer?, Integer?] 25 | def baz: -> Integer? 26 | end 27 | -------------------------------------------------------------------------------- /scenario/array/rbs_tuple2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: ([Integer]) -> :a 4 | | ([Integer, Integer]) -> :b 5 | | ([Integer, String]) -> :c 6 | end 7 | 8 | ## update: test.rb 9 | def test1 10 | C.new.foo([1]) 11 | end 12 | 13 | def test2 14 | C.new.foo(["str"]) 15 | end 16 | 17 | def test3 18 | C.new.foo([1, 2]) 19 | end 20 | 21 | def test4 22 | C.new.foo([1, "str"]) 23 | end 24 | 25 | def test5 26 | C.new.foo(["str", "str"]) 27 | end 28 | 29 | ## assert 30 | class Object 31 | def test1: -> :a 32 | def test2: -> untyped 33 | def test3: -> :b 34 | def test4: -> :c 35 | def test5: -> untyped 36 | end 37 | -------------------------------------------------------------------------------- /scenario/array/splat.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | [*1..100] 4 | end 5 | def bar 6 | [*"A".."Z"] 7 | end 8 | 9 | ## assert 10 | class Object 11 | def foo: -> Array[Integer] 12 | def bar: -> Array[String] 13 | end 14 | -------------------------------------------------------------------------------- /scenario/array/splat2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def to_a 4 | [1, "str"] 5 | end 6 | end 7 | def check 8 | [*Foo.new] 9 | end 10 | 11 | ## assert 12 | class Foo 13 | def to_a: -> [Integer, String] 14 | end 15 | class Object 16 | def check: -> Array[Integer | String] 17 | end 18 | -------------------------------------------------------------------------------- /scenario/array/tuple_aref.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | ary = [1, "str"] 4 | ary[0] 5 | end 6 | 7 | def bar 8 | ary = [1, "str"] 9 | i = 0 10 | ary[i] 11 | end 12 | 13 | ## assert 14 | class Object 15 | def foo: -> Integer 16 | def bar: -> (Integer | String) 17 | end 18 | -------------------------------------------------------------------------------- /scenario/array/tuple_aset.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | ary = [1, "str"] 4 | ary[0] = 1.0 5 | ary[0] 6 | end 7 | 8 | ## assert 9 | class Object 10 | def foo: -> (Float | Integer) 11 | end 12 | -------------------------------------------------------------------------------- /scenario/block/anonymous_block_forwarding.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&) 3 | bar(&) 4 | end 5 | 6 | def bar(&b) 7 | b.call(1.0) 8 | end 9 | 10 | foo do |n| 11 | "str" 12 | end 13 | 14 | ## assert 15 | class Object 16 | def foo: { (Float) -> String } -> String 17 | def bar: { (Float) -> String } -> String 18 | end 19 | -------------------------------------------------------------------------------- /scenario/block/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n, &b) 3 | b.call(1.0) 4 | end 5 | 6 | foo(12) do |n| 7 | "str" 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: (Integer) { (Float) -> String } -> String 13 | end 14 | -------------------------------------------------------------------------------- /scenario/block/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def bar(n) 3 | yield 1.0 4 | end 5 | 6 | bar(12) do |n| 7 | "str" 8 | end 9 | 10 | ## assert 11 | class Object 12 | def bar: (Integer) { (Float) -> String } -> String 13 | end 14 | -------------------------------------------------------------------------------- /scenario/block/block_pass.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | yield 42 4 | end 5 | 6 | def proxy(&blk) 7 | foo(&blk) 8 | end 9 | 10 | def bar 11 | ret = nil 12 | foo do |n| 13 | ret = n 14 | end 15 | ret 16 | end 17 | 18 | ## assert 19 | class Object 20 | def foo: { (Integer) -> Integer } -> Integer 21 | def proxy: { (Integer) -> Integer } -> Integer 22 | def bar: -> Integer? 23 | end 24 | 25 | ## update 26 | def foo(x) 27 | yield 42 28 | end 29 | 30 | def proxy(&blk) 31 | foo(1, &blk) 32 | end 33 | 34 | def bar 35 | ret = nil 36 | foo(1) do |n| 37 | ret = n 38 | end 39 | ret 40 | end 41 | 42 | ## assert 43 | class Object 44 | def foo: (Integer) { (Integer) -> Integer } -> Integer 45 | def proxy: { (Integer) -> Integer } -> Integer 46 | def bar: -> Integer? 47 | end 48 | -------------------------------------------------------------------------------- /scenario/block/it.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&b) 3 | b.call(1) 4 | end 5 | 6 | foo do 7 | it 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: { (Integer) -> Integer } -> Integer 13 | end 14 | -------------------------------------------------------------------------------- /scenario/block/numbered_parameter.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&b) 3 | b.call(1, '') 4 | end 5 | 6 | foo do 7 | [_1, _2] 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: { (Integer, String) -> [Integer, String] } -> [Integer, String] 13 | end 14 | -------------------------------------------------------------------------------- /scenario/block/rbs_block.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | 1.times {|_| } 4 | end 5 | 6 | def bar 7 | 1.times # TODO: type parameter of Enumerator 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> Integer 13 | def bar: -> Enumerator[Integer, Integer] 14 | end 15 | -------------------------------------------------------------------------------- /scenario/block/rbs_block2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: [X] { () -> Integer } -> String 4 | end 5 | 6 | ## update: test.rb 7 | def test 8 | ## TODO: we should report a wrong return type of block 9 | foo { "str" } 10 | end 11 | 12 | ## assert: test.rb 13 | class Object 14 | def test: -> String 15 | end 16 | -------------------------------------------------------------------------------- /scenario/block/rbs_block3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: [X] { () -> X } -> X 4 | end 5 | 6 | ## update: test.rb 7 | def test 8 | foo { 1 } 9 | end 10 | 11 | ## assert: test.rb 12 | class Object 13 | def test: -> Integer 14 | end 15 | -------------------------------------------------------------------------------- /scenario/block/rbs_block4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: [R] { (Integer) -> R } -> R 4 | end 5 | 6 | ## update: test.rb 7 | def test 8 | foo {|x| x.to_s } 9 | end 10 | 11 | def test2 12 | [1, "str", 1.0].map {|x| [x, x.to_s] } 13 | end 14 | 15 | ## assert: test.rb 16 | class Object 17 | def test: -> String 18 | def test2: -> Array[[Float | Integer | String, String]] 19 | end 20 | -------------------------------------------------------------------------------- /scenario/block/rbs_block5.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def yield_ary: { ([Integer, String]) -> untyped } -> void 4 | end 5 | 6 | ## update: test.rb 7 | def accept_x 8 | yield_ary {|x| return x } 9 | nil 10 | end 11 | def accept_x_y_z 12 | yield_ary {|x, y, z| return [x, y, z] } 13 | nil 14 | end 15 | 16 | ## assert 17 | class Object 18 | def accept_x: -> [Integer, String]? 19 | def accept_x_y_z: -> [Integer, String, untyped]? 20 | end 21 | 22 | ## update: test.rbs 23 | class Object 24 | def yield_ary: { (Integer, String) -> untyped } -> void 25 | end 26 | 27 | ## update: test.rb 28 | def accept_x 29 | yield_ary {|x| return x } 30 | nil 31 | end 32 | def accept_x_y_z 33 | yield_ary {|x, y, z| return [x, y, z] } 34 | nil 35 | end 36 | 37 | ## assert 38 | class Object 39 | def accept_x: -> Integer? 40 | def accept_x_y_z: -> [Integer, String, untyped]? 41 | end 42 | -------------------------------------------------------------------------------- /scenario/block/rbs_block6.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def foo(h) 3 | h.each do |k, v| 4 | return v 5 | end 6 | nil 7 | end 8 | 9 | foo({ a: 42 }) 10 | foo({ b: "str" }) 11 | 12 | ## assert 13 | class Object 14 | def foo: (Hash[:a, Integer] | Hash[:b, String]) -> (Integer | String)? 15 | end 16 | -------------------------------------------------------------------------------- /scenario/block/rbs_block7.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: { () -> Integer } -> void 4 | end 5 | 6 | ## update: test.rb 7 | Foo.new.foo do 8 | "str" 9 | end 10 | 11 | ## diagnostics: test.rb 12 | (2,2)-(2,7): expected: Integer; actual: String 13 | 14 | ## update: test.rbs 15 | class Foo 16 | def foo: { () -> String } -> void 17 | end 18 | 19 | ## diagnostics: test.rb 20 | -------------------------------------------------------------------------------- /scenario/class/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def initialize(n) 4 | n 5 | end 6 | 7 | def foo(n) 8 | C 9 | end 10 | end 11 | 12 | C.new(1).foo("str") 13 | 14 | ## assert 15 | class C 16 | def initialize: (Integer) -> Integer 17 | def foo: (String) -> singleton(C) 18 | end 19 | -------------------------------------------------------------------------------- /scenario/class/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | class D 4 | def foo(n) 5 | C 6 | end 7 | end 8 | end 9 | 10 | C::D.new(1).foo("str") 11 | 12 | ## assert 13 | class C 14 | class C::D 15 | def foo: (String) -> singleton(C) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /scenario/class/circular.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class A < B 3 | end 4 | 5 | class B < A 6 | end 7 | 8 | module M 9 | include M 10 | end 11 | 12 | ## assert 13 | class A < B 14 | end 15 | class B # failed to identify its superclass 16 | end 17 | module M 18 | end 19 | -------------------------------------------------------------------------------- /scenario/class/dynamic.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module 1::C 3 | end 4 | 5 | class 1::C 6 | end 7 | 8 | ## diagnostics 9 | (1,0)-(2,3): TypeProf cannot analyze a non-static module 10 | (4,0)-(5,3): TypeProf cannot analyze a non-static class 11 | 12 | ## update 13 | Class.new do 14 | class << self 15 | def foo = :ok 16 | end 17 | end 18 | 19 | ## diagnostics 20 | (2,2)-(4,5): TypeProf cannot analyze a non-static class 21 | -------------------------------------------------------------------------------- /scenario/class/include-hack.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module Foo 3 | module Bar 4 | end 5 | end 6 | 7 | module Baz 8 | include Foo 9 | include Bar 10 | end 11 | 12 | ## assert 13 | module Foo 14 | module Foo::Bar 15 | end 16 | end 17 | module Baz 18 | end 19 | -------------------------------------------------------------------------------- /scenario/class/initialize.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class A 3 | end 4 | 5 | class B 6 | def initialize(xxx) # 5 7 | @xxx = xxx 8 | end 9 | end 10 | 11 | class C 12 | end 13 | 14 | def foo 15 | B.new(1) # 14 16 | end 17 | 18 | ## assert 19 | class A 20 | end 21 | class B 22 | def initialize: (Integer) -> Integer 23 | end 24 | class C 25 | end 26 | class Object 27 | def foo: -> B 28 | end 29 | 30 | ## hover: test.rb:5:19 31 | Integer 32 | 33 | ## hover: test.rb:14:6 34 | B#initialize : (Integer) -> Integer 35 | -------------------------------------------------------------------------------- /scenario/class/initialize2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def initialize(n) 4 | end 5 | end 6 | 7 | class Bar 8 | def initialize(n) 9 | end 10 | end 11 | 12 | def my_new(klass) 13 | klass.new(1) 14 | end 15 | 16 | my_new(Foo) 17 | my_new(Bar) 18 | 19 | ## assert 20 | class Foo 21 | def initialize: (Integer) -> nil 22 | end 23 | class Bar 24 | def initialize: (Integer) -> nil 25 | end 26 | class Object 27 | def my_new: (singleton(Bar) | singleton(Foo)) -> (Bar | Foo) 28 | end 29 | -------------------------------------------------------------------------------- /scenario/class/initialize3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def initialize(n) 4 | yield "string" 5 | end 6 | end 7 | 8 | def test 9 | Foo.new(1) do |x| 10 | return x 11 | end 12 | end 13 | 14 | ## assert 15 | class Foo 16 | def initialize: (Integer) { (String) -> bot } -> bot 17 | end 18 | class Object 19 | def test: -> (Foo | String) 20 | end 21 | -------------------------------------------------------------------------------- /scenario/class/module.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module M 3 | def foo 4 | 42 5 | end 6 | end 7 | 8 | class C 9 | include M 10 | def bar 11 | foo 12 | end 13 | end 14 | 15 | ## assert 16 | module M 17 | def foo: -> Integer 18 | end 19 | class C 20 | include M 21 | def bar: -> Integer 22 | end 23 | -------------------------------------------------------------------------------- /scenario/class/module2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module M1 3 | def foo(n) 4 | end 5 | end 6 | 7 | module M2 8 | include M1 9 | end 10 | 11 | module M3 12 | def bar(n) 13 | end 14 | end 15 | 16 | module M4 17 | include M3 18 | def foo(n) 19 | bar(n) 20 | end 21 | end 22 | 23 | class C 24 | include M2 25 | include M4 26 | end 27 | 28 | C.new.foo(:test) 29 | 30 | ## assert 31 | module M1 32 | def foo: (:test) -> nil 33 | end 34 | module M2 35 | end 36 | module M3 37 | def bar: (:test) -> nil 38 | end 39 | module M4 40 | def foo: (:test) -> nil 41 | end 42 | class C 43 | include M2 44 | include M4 45 | end 46 | -------------------------------------------------------------------------------- /scenario/class/rbs_class.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (singleton(C)) -> :ok 4 | def bar: (Class) -> :ok 5 | end 6 | 7 | ## update: test.rb 8 | def test1 9 | C.new.foo(C) 10 | end 11 | 12 | def test2 13 | C.new.foo(C) 14 | end 15 | 16 | ## assert 17 | class Object 18 | def test1: -> :ok 19 | def test2: -> :ok 20 | end 21 | -------------------------------------------------------------------------------- /scenario/class/rbs_module.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | rand # Kernel#rand 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> Float 9 | end 10 | -------------------------------------------------------------------------------- /scenario/class/rbs_module2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M[X] 3 | def foo: -> X 4 | end 5 | 6 | class Foo 7 | include M[Integer] 8 | include M[String] 9 | end 10 | 11 | ## update: test.rb 12 | def test 13 | Foo.new.foo 14 | end 15 | 16 | ## assert: test.rb 17 | class Object 18 | def test: -> (Integer | String) 19 | end 20 | -------------------------------------------------------------------------------- /scenario/class/rbs_module3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M2[X] 3 | def foo: -> X 4 | end 5 | 6 | module M[X] 7 | include M2[[X, X]] 8 | end 9 | 10 | class Foo 11 | include M[Integer] 12 | end 13 | 14 | ## update: test.rb 15 | def test 16 | Foo.new.foo 17 | end 18 | 19 | ## assert: test.rb 20 | class Object 21 | def test: -> [Integer, Integer] 22 | end 23 | -------------------------------------------------------------------------------- /scenario/class/rbs_self_types1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Fooable 3 | def foo: (Integer) -> String 4 | end 5 | 6 | module M: _Fooable 7 | end 8 | 9 | ## update: test.rb 10 | class C 11 | include M 12 | end 13 | 14 | def test 15 | C.new.foo(42) 16 | end 17 | 18 | ## assert 19 | class C 20 | include M 21 | end 22 | class Object 23 | def test: -> String 24 | end 25 | -------------------------------------------------------------------------------- /scenario/class/rbs_self_types2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Fooable[X] 3 | def foo: (Integer) -> [X, String] 4 | end 5 | 6 | module M[X]: _Fooable[X] 7 | end 8 | 9 | module N: M[Float] 10 | end 11 | 12 | ## update: test.rb 13 | class C 14 | include N 15 | end 16 | 17 | def test 18 | C.new.foo(42) 19 | end 20 | 21 | ## assert 22 | class C 23 | include N 24 | end 25 | class Object 26 | def test: -> [Float, String] 27 | end 28 | -------------------------------------------------------------------------------- /scenario/class/rbs_self_types3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Fooable 3 | def foo: -> :FOO 4 | end 5 | 6 | interface _Barable 7 | def bar: -> :BAR 8 | end 9 | 10 | module M: _Fooable, _Barable 11 | end 12 | 13 | ## update: test.rb 14 | class C 15 | include M 16 | end 17 | 18 | def test 19 | [C.new.foo, C.new.bar] 20 | end 21 | 22 | ## assert 23 | class C 24 | include M 25 | end 26 | class Object 27 | def test: -> [:FOO, :BAR] 28 | end 29 | -------------------------------------------------------------------------------- /scenario/class/self-in-cbase.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | class self::Bar::Baz 4 | end 5 | end 6 | 7 | ## assert 8 | class Foo 9 | class Foo::Bar::Baz 10 | end 11 | end 12 | 13 | ## update 14 | class self::X 15 | end 16 | 17 | ## assert 18 | 19 | ## diagnostics 20 | (1,0)-(2,3): TypeProf cannot analyze a non-static class 21 | -------------------------------------------------------------------------------- /scenario/class/singleton_class.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class << Time 3 | def foo = :ok 4 | end 5 | 6 | ## assert 7 | class Time 8 | def self.foo: -> :ok 9 | end 10 | 11 | ## update 12 | class Foo 13 | class << self 14 | def foo = :ok 15 | end 16 | end 17 | 18 | ## assert 19 | class Foo 20 | def self.foo: -> :ok 21 | end 22 | 23 | ## update 24 | class Bar; end 25 | 26 | class Foo < Bar 27 | class << self 28 | def foo = :ok 29 | end 30 | end 31 | 32 | ## assert 33 | class Bar 34 | end 35 | class Foo < Bar 36 | def self.foo: -> :ok 37 | end 38 | 39 | ## update 40 | class Foo 41 | def self.foo 42 | (class << self; self; end) 43 | end 44 | end 45 | 46 | ## assert 47 | class Foo 48 | def self.foo: -> untyped 49 | end 50 | -------------------------------------------------------------------------------- /scenario/class/unknown-cbase.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo::Bar 3 | class C 4 | def foo 5 | 1 6 | end 7 | end 8 | end 9 | 10 | # Currently, Foo::Bar::C cannot be resolved because there is no definition of Foo 11 | class D < Foo::Bar::C 12 | def check = foo 13 | end 14 | 15 | ## assert: test.rb 16 | class Foo::Bar 17 | class Foo::Bar::C 18 | def foo: -> Integer 19 | end 20 | end 21 | class D # failed to identify its superclass 22 | def check: -> untyped 23 | end 24 | 25 | ## update: test.rbs 26 | module Foo 27 | end 28 | 29 | ## assert: test.rb 30 | class Foo::Bar 31 | class Foo::Bar::C 32 | def foo: -> Integer 33 | end 34 | end 35 | class D < Foo::Bar::C 36 | def check: -> Integer 37 | end 38 | -------------------------------------------------------------------------------- /scenario/const/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | X = 1 4 | end 5 | 6 | class D < C 7 | end 8 | 9 | def foo(_) 10 | D::X 11 | end 12 | 13 | ## assert 14 | class C 15 | C::X: Integer 16 | end 17 | class D < C 18 | end 19 | class Object 20 | def foo: (untyped) -> Integer 21 | end 22 | -------------------------------------------------------------------------------- /scenario/const/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | C = 1 3 | class Foo 4 | C = 1.0 5 | def foo 6 | ::C 7 | end 8 | end 9 | Foo::Bar = :bar 10 | 11 | ## assert 12 | C: Integer 13 | class Foo 14 | Foo::C: Float 15 | def foo: -> Integer 16 | end 17 | Foo::Bar: :bar 18 | -------------------------------------------------------------------------------- /scenario/const/circular.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def target = C::C 4 | end 5 | 6 | ## assert 7 | class C 8 | def target: -> untyped 9 | end 10 | -------------------------------------------------------------------------------- /scenario/const/dynamic.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | mod = Module.new 3 | CHECK = mod::Foo = 42 4 | 5 | ## assert 6 | CHECK: Integer 7 | -------------------------------------------------------------------------------- /scenario/const/module_const.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module M 3 | C = :test 4 | end 5 | 6 | class C 7 | include M 8 | end 9 | 10 | def check 11 | C::C 12 | end 13 | 14 | ## diagnostics 15 | ## assert 16 | module M 17 | M::C: :test 18 | end 19 | class C 20 | include M 21 | end 22 | class Object 23 | def check: -> :test 24 | end 25 | -------------------------------------------------------------------------------- /scenario/const/rbs_const.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | RUBY_VERSION 4 | end 5 | 6 | def bar 7 | ENV["foo"] 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> String 13 | def bar: -> String? 14 | end 15 | -------------------------------------------------------------------------------- /scenario/const/resolve.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | module M 3 | class A 4 | end 5 | end 6 | 7 | ## update: test1.rb 8 | module M 9 | class B 10 | # Defining M::B iterates its const_reads and fires the following 11 | # BaseConstRead (M) and ScopedConstRead (M::A). 12 | # The ScopedConstRead attempts to add itself to M's const_reads. 13 | # This addition is done during the iteration of M's const_reads, 14 | # so we need to avoid "modification during iteration". 15 | M::A 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /scenario/const/superclass1.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | end 4 | 5 | class D 6 | class E < C 7 | end 8 | end 9 | 10 | ## assert: test0.rb 11 | class C 12 | end 13 | class D 14 | class D::E < C 15 | end 16 | end 17 | 18 | ## update: test1.rb 19 | class D 20 | class C # Defining D::C changes the superclass of D::E from ::C to D::C 21 | end 22 | end 23 | 24 | ## assert: test0.rb 25 | class C 26 | end 27 | class D 28 | class D::E < D::C 29 | end 30 | end 31 | 32 | ## update: test1.rb 33 | class D 34 | # Removing D::C restores the superclass of D::E back to ::C 35 | end 36 | 37 | ## assert: test0.rb 38 | class C 39 | end 40 | class D 41 | class D::E < C 42 | end 43 | end 44 | 45 | -------------------------------------------------------------------------------- /scenario/const/superclass2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class A 3 | class B 4 | end 5 | end 6 | 7 | class X 8 | class C < A::B 9 | end 10 | end 11 | 12 | ## assert: test0.rb 13 | class A 14 | class A::B 15 | end 16 | end 17 | class X 18 | class X::C < A::B 19 | end 20 | end 21 | 22 | ## update: test1.rb 23 | class X 24 | class A 25 | # This affects the superclass of X::C 26 | end 27 | end 28 | 29 | ## assert: test0.rb 30 | class A 31 | class A::B 32 | end 33 | end 34 | class X 35 | class X::C # failed to identify its superclass 36 | end 37 | end 38 | 39 | 40 | ## update: test1.rb 41 | class X 42 | class A 43 | class B 44 | end 45 | end 46 | end 47 | 48 | ## assert: test0.rb 49 | class A 50 | class A::B 51 | end 52 | end 53 | class X 54 | class X::C < X::A::B 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /scenario/const/superclass3.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class A 3 | class B 4 | end 5 | end 6 | 7 | class X 8 | class C < A 9 | class D < B 10 | end 11 | end 12 | end 13 | 14 | ## assert: test0.rb 15 | class A 16 | class A::B 17 | end 18 | end 19 | class X 20 | class X::C < A 21 | class X::C::D < A::B 22 | end 23 | end 24 | end 25 | 26 | ## update: test1.rb 27 | class X 28 | class A 29 | class B 30 | end 31 | end 32 | end 33 | 34 | ## assert: test0.rb 35 | class A 36 | class A::B 37 | end 38 | end 39 | class X 40 | class X::C < X::A 41 | class X::C::D < X::A::B 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /scenario/const/superclass4.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | end 4 | 5 | class D 6 | def foo 7 | C.new 8 | end 9 | end 10 | 11 | ## assert: test0.rb 12 | class C 13 | end 14 | class D 15 | def foo: -> C 16 | end 17 | 18 | ## update: test1.rb 19 | class D 20 | class C 21 | end 22 | end 23 | 24 | ## assert: test0.rb 25 | class C 26 | end 27 | class D 28 | def foo: -> D::C 29 | end 30 | 31 | ## update: test1.rb 32 | class D 33 | end 34 | 35 | ## assert: test0.rb 36 | class C 37 | end 38 | class D 39 | def foo: -> C 40 | end 41 | -------------------------------------------------------------------------------- /scenario/control/and.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x, y) 3 | x && y 4 | end 5 | 6 | foo(1, "s") 7 | 8 | ## assert 9 | class Object 10 | def foo: (Integer, String) -> (Integer | String) 11 | end 12 | -------------------------------------------------------------------------------- /scenario/control/begin-variable-tracking.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | x = :a 4 | begin 5 | x = :b 6 | raise 7 | x = :c 8 | rescue 9 | check_rescue(x) 10 | x = :d 11 | else 12 | check_else(x) 13 | x = :e 14 | ensure 15 | check_ensure(x) 16 | x = :f 17 | end 18 | check_after(x) 19 | end 20 | 21 | def check_rescue(n) = nil 22 | def check_else(n) = nil 23 | def check_ensure(n) = nil 24 | def check_after(n) = nil 25 | 26 | ## assert 27 | class Object 28 | def foo: -> nil 29 | def check_rescue: (:a | :c) -> nil 30 | def check_else: (:c) -> nil 31 | def check_ensure: (:a | :c | :d | :e) -> nil 32 | def check_after: (:a | :c | :d | :e | :f) -> nil 33 | end 34 | -------------------------------------------------------------------------------- /scenario/control/begin.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | begin 4 | 1 5 | rescue 6 | "str" 7 | end 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> (Integer | String) 13 | end 14 | 15 | ## update 16 | def foo 17 | begin 18 | 1 19 | ensure 20 | "str" 21 | end 22 | end 23 | 24 | ## assert 25 | class Object 26 | def foo: -> Integer 27 | end 28 | 29 | 30 | ## update 31 | def foo 32 | begin 33 | 1 34 | rescue 35 | "str" 36 | else 37 | true 38 | end 39 | end 40 | 41 | ## assert 42 | class Object 43 | def foo: -> (Integer | String | true) 44 | end 45 | 46 | ## update 47 | def foo 48 | begin 49 | 1 50 | rescue 51 | "str" 52 | else 53 | true 54 | ensure 55 | false 56 | end 57 | end 58 | 59 | ## assert 60 | class Object 61 | def foo: -> (Integer | String | true) 62 | end 63 | 64 | ## update 65 | def foo 66 | begin 67 | rescue 68 | else 69 | ensure 70 | end 71 | end 72 | 73 | ## assert 74 | class Object 75 | def foo: -> nil 76 | end 77 | -------------------------------------------------------------------------------- /scenario/control/bot.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | raise "foo" unless n 4 | n 5 | end 6 | 7 | foo(1) 8 | foo(nil) 9 | 10 | ## assert 11 | class Object 12 | def foo: (Integer?) -> Integer 13 | end 14 | -------------------------------------------------------------------------------- /scenario/control/bot2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | if n 4 | n = raise 5 | # TODO: if any statement returns a bot type, the whole block should also do so? 6 | 1 7 | end 8 | n 9 | end 10 | 11 | def bar(n) 12 | if n 13 | n = raise 14 | end 15 | n 16 | end 17 | 18 | ## assert 19 | class Object 20 | def foo: (untyped) -> bot 21 | def bar: (untyped) -> untyped 22 | end 23 | -------------------------------------------------------------------------------- /scenario/control/bot3.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | n = raise 4 | n.bar 5 | end 6 | 7 | ## assert 8 | class Object 9 | def foo: -> untyped 10 | end 11 | 12 | ## diagnostics 13 | -------------------------------------------------------------------------------- /scenario/control/bot4.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | ary = [] 4 | n = 0 5 | 1.times do |x| 6 | if x == 1 7 | if x == 1 8 | ary << "" 9 | n += 1 10 | end 11 | end 12 | end 13 | end 14 | 15 | ## update 16 | def foo 17 | ary = [] 18 | n = 0 19 | 1.times do |x| 20 | if x == 1 21 | if x == 1 22 | ary << "" 23 | n += 1 24 | end 25 | end 26 | end 27 | end 28 | 29 | ## assert 30 | class Object 31 | def foo: -> Integer 32 | end 33 | -------------------------------------------------------------------------------- /scenario/control/branch.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | n ? 1 : "str" 4 | end 5 | def bar(n) 6 | n = 1 if n 7 | n 8 | end 9 | def baz(n) 10 | n = 1 unless n 11 | end 12 | 13 | ## assert 14 | class Object 15 | def foo: (untyped) -> (Integer | String) 16 | def bar: (untyped) -> Integer 17 | def baz: (untyped) -> Integer? 18 | end 19 | 20 | ## update 21 | def foo(n) 22 | n ? 1 : "str" 23 | end 24 | def bar(n) 25 | n = 1 if n 26 | n 27 | end 28 | def baz(n) 29 | n = 1 unless n 30 | end 31 | 32 | ## assert 33 | class Object 34 | def foo: (untyped) -> (Integer | String) 35 | def bar: (untyped) -> Integer 36 | def baz: (untyped) -> Integer? 37 | end 38 | 39 | 40 | ## update 41 | def foo 42 | if true 43 | :ok 44 | else 45 | :fail 46 | end 47 | end 48 | 49 | ## assert 50 | class Object 51 | def foo: -> (:fail | :ok) 52 | end 53 | -------------------------------------------------------------------------------- /scenario/control/break.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | yield 1 4 | "str" 5 | end 6 | 7 | def bar 8 | foo do |n| 9 | break 10 | 1.0 11 | end 12 | end 13 | 14 | # TODO: These expectation are wrong! Need to implement break correctly 15 | 16 | ## assert 17 | class Object 18 | def foo: { (Integer) -> Float } -> String 19 | def bar: -> String? 20 | end 21 | 22 | ## update: test.rb 23 | def foo 24 | loop do 25 | break 1 26 | end 27 | end 28 | 29 | ## assert 30 | class Object 31 | def foo: -> Integer 32 | end 33 | -------------------------------------------------------------------------------- /scenario/control/case.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | case n 4 | when 1 5 | 1 6 | when 2 7 | "str" 8 | else 9 | 1.0 10 | end 11 | end 12 | 13 | def bar(n) 14 | case n 15 | when 1 16 | 1 17 | when 2 18 | "str" 19 | end 20 | end 21 | 22 | def baz(n) 23 | case n 24 | when 1 25 | 1 26 | when 2 27 | "str" 28 | else 29 | raise 30 | end 31 | end 32 | 33 | def qux(n) 34 | case n 35 | when 1 36 | when 2 37 | else 38 | end 39 | end 40 | 41 | def without_predicate(n) 42 | case 43 | when true 44 | 1 45 | end 46 | end 47 | 48 | ## assert 49 | class Object 50 | def foo: (untyped) -> (Float | Integer | String) 51 | def bar: (untyped) -> (Integer | String)? 52 | def baz: (untyped) -> (Integer | String) 53 | def qux: (untyped) -> nil 54 | def without_predicate: (untyped) -> Integer? 55 | end 56 | -------------------------------------------------------------------------------- /scenario/control/elsif.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def elsif_and_block 3 | if true 4 | elsif true 5 | else 6 | w = 0 7 | end 8 | 9 | yield_self do 10 | w = 0 11 | end 12 | 13 | 1 14 | end 15 | 16 | ## assert 17 | class Object 18 | def elsif_and_block: -> Integer 19 | end 20 | -------------------------------------------------------------------------------- /scenario/control/empty.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | if x 4 | end 5 | end 6 | 7 | def bar(x) 8 | if x 9 | else 10 | end 11 | end 12 | 13 | def baz(x) 14 | while x 15 | end 16 | end 17 | 18 | ## assert 19 | class Object 20 | def foo: (untyped) -> nil 21 | def bar: (untyped) -> nil 22 | def baz: (untyped) -> nil 23 | end 24 | -------------------------------------------------------------------------------- /scenario/control/ensure.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def bar(n) 3 | end 4 | 5 | def foo(n) 6 | n = "str" 7 | 1.0 8 | ensure 9 | bar(n) 10 | end 11 | 12 | foo(1) 13 | 14 | ## assert 15 | class Object 16 | def bar: (Integer | String) -> nil 17 | def foo: (Integer) -> Float 18 | end 19 | -------------------------------------------------------------------------------- /scenario/control/loop.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | a = [[nil]] 4 | while a 5 | a = a[0] 6 | end 7 | a 8 | end 9 | 10 | def bar 11 | a = [[nil]] 12 | until a 13 | a = a[0] 14 | end 15 | a 16 | end 17 | 18 | def baz 19 | a = [[nil]] 20 | begin a 21 | a = a[0] 22 | end while a 23 | a 24 | end 25 | 26 | def qux 27 | a = b = [[nil]] 28 | while a 29 | a = a[0] 30 | b = b[0] # 29 31 | end 32 | b 33 | end 34 | 35 | ## assert 36 | class Object 37 | def foo: -> nil 38 | def bar: -> [[nil]] 39 | def baz: -> nil 40 | def qux: -> ([[nil]] | [nil])? 41 | end 42 | 43 | ## diagnostics 44 | (29,9)-(29,12): undefined method: nil#[] 45 | -------------------------------------------------------------------------------- /scenario/control/loop2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def test 3 | a = "foo" 4 | while true 5 | a = a.sum 6 | end 7 | end 8 | 9 | ## assert 10 | class Object 11 | def test: -> nil 12 | end 13 | 14 | ## diagnostics 15 | (4,10)-(4,13): undefined method: Integer#sum 16 | -------------------------------------------------------------------------------- /scenario/control/next-in-loop.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | until true 4 | next 5 | end 6 | 7 | while false 8 | next 9 | end 10 | end 11 | 12 | ## assert 13 | class Object 14 | def foo: -> nil 15 | end 16 | 17 | ## update 18 | def bar 19 | yield 20 | nil 21 | end 22 | 23 | def foo 24 | bar do 25 | next :a 26 | until true 27 | next :b 28 | end 29 | next :c 30 | end 31 | end 32 | 33 | ## assert 34 | class Object 35 | def bar: { () -> (:a | :c) } -> nil 36 | def foo: -> nil 37 | end 38 | -------------------------------------------------------------------------------- /scenario/control/next.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | yield 42 4 | end 5 | 6 | foo do |n| 7 | next 1 8 | "str" 9 | end 10 | 11 | ## assert 12 | class Object 13 | def foo: { (Integer) -> (Integer | String) } -> (Integer | String) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/control/next2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | yield 1 4 | yield "str" 5 | end 6 | 7 | foo do |x| 8 | next 1 unless x.is_a?(Integer) 9 | x + 1 10 | end 11 | 12 | ## diagnostics 13 | -------------------------------------------------------------------------------- /scenario/control/next3.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | yield 42 4 | end 5 | 6 | foo do |n| 7 | next 1, 2 8 | "str" 9 | end 10 | 11 | ## assert 12 | class Object 13 | def foo: { (Integer) -> (String | [Integer, Integer]) } -> (String | [Integer, Integer]) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/control/or.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x, y) 3 | x || y 4 | end 5 | 6 | foo(1, "s") 7 | 8 | ## assert 9 | class Object 10 | def foo: (Integer, String) -> (Integer | String) 11 | end 12 | -------------------------------------------------------------------------------- /scenario/control/raise-bot.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | if rand > 0.5 4 | raise 5 | end 6 | rescue 7 | 1 8 | end 9 | 10 | def bar 11 | raise 12 | rescue 13 | 1 14 | end 15 | 16 | ## diagnostics 17 | 18 | ## assert 19 | class Object 20 | def foo: -> Integer? 21 | def bar: -> Integer 22 | end 23 | -------------------------------------------------------------------------------- /scenario/control/redo.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | end 4 | 5 | def bar 6 | foo do |_| 7 | redo 8 | end 9 | end 10 | 11 | ## assert 12 | class Object 13 | def foo: -> nil 14 | def bar: -> nil 15 | end 16 | -------------------------------------------------------------------------------- /scenario/control/rescue-assign.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | raise if n != 0 4 | n.to_s 5 | rescue StandardError => e 6 | e.message 7 | end 8 | 9 | def bar(n) 10 | raise if n != 0 11 | n.to_s 12 | rescue *[StandardError] => e 13 | e.message 14 | end 15 | 16 | foo(1) 17 | bar(1) 18 | 19 | ## diagnostics 20 | 21 | ## assert 22 | class Object 23 | def foo: (Integer) -> String 24 | def bar: (Integer) -> String 25 | end 26 | -------------------------------------------------------------------------------- /scenario/control/rescue-splat.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | begin 4 | :a 5 | rescue *[StandardError] 6 | :b 7 | end 8 | end 9 | 10 | foo 11 | 12 | ## assert 13 | class Object 14 | def foo: -> (:a | :b) 15 | end 16 | -------------------------------------------------------------------------------- /scenario/control/rescue.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | begin 4 | :a 5 | rescue 6 | :b 7 | rescue SyntaxError 8 | :c 9 | rescue Exception 10 | :d 11 | else 12 | :e 13 | end 14 | end 15 | 16 | def bar(n) 17 | n rescue :a 18 | end 19 | 20 | foo 21 | bar(1) 22 | 23 | ## assert 24 | class Object 25 | def foo: -> (:a | :b | :c | :d | :e) 26 | def bar: (Integer) -> (:a | Integer) 27 | end 28 | -------------------------------------------------------------------------------- /scenario/control/retry.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | begin 4 | n = "str" if n == 1 5 | raise if n == "str" 6 | :c 7 | rescue SyntaxError 8 | bar(n) 9 | rescue Exception 10 | n = 2 11 | retry 12 | 1.0 13 | else 14 | :b 15 | end 16 | end 17 | 18 | def bar(n) 19 | :a 20 | end 21 | 22 | foo(1) 23 | 24 | ## assert 25 | class Object 26 | def foo: (Integer) -> (:a | :b | :c | Float) 27 | def bar: (Integer | String) -> :a 28 | end 29 | -------------------------------------------------------------------------------- /scenario/control/return.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | return if x 4 | "str" 5 | end 6 | 7 | def bar(x) 8 | return 1 if x 9 | "str" 10 | end 11 | 12 | def baz(x) 13 | 1.times do |_| 14 | return 1 15 | end 16 | "str" 17 | end 18 | 19 | ## assert 20 | class Object 21 | def foo: (untyped) -> String? 22 | def bar: (untyped) -> (Integer | String) 23 | def baz: (untyped) -> (Integer | String) 24 | end 25 | -------------------------------------------------------------------------------- /scenario/control/return2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | return 1, 2 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> [Integer, Integer] 9 | end 10 | -------------------------------------------------------------------------------- /scenario/definitions/definition-rbs.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module Animal 3 | class Cat 4 | def call_1: () -> void 5 | def call_2: () -> void 6 | end 7 | end 8 | 9 | ## update: test.rb 10 | module Animal 11 | class Cat 12 | def call_1 13 | puts "meow" 14 | end 15 | end 16 | end 17 | 18 | Animal::Cat.new.call_1 19 | Animal::Cat.new.call_2 20 | 21 | ## definition: test.rb:9:17 22 | test.rbs:(3,8)-(3,14) 23 | test.rb:(3,8)-(3,14) 24 | 25 | ## definition: test.rb:10:17 26 | test.rbs:(4,8)-(4,14) 27 | -------------------------------------------------------------------------------- /scenario/definitions/definition.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | module Animal 3 | class Cat 4 | def call 5 | puts "meow" 6 | end 7 | end 8 | end 9 | 10 | Animal::Cat.new.call 11 | 12 | ## definition: test.rb:9:1 13 | test.rb:(1,7)-(1,13) 14 | 15 | ## definition: test.rb:9:9 16 | test.rb:(2,8)-(2,11) 17 | 18 | ## definition: test.rb:9:17 19 | test.rb:(3,8)-(3,12) 20 | -------------------------------------------------------------------------------- /scenario/definitions/definition_multibyte_characters.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | module A動物 3 | class B猫 4 | def 🐱🐱🐱 5 | puts "にゃー" 6 | end 7 | end 8 | end 9 | 10 | A動物::B猫.new.🐱🐱🐱 11 | 12 | ## definition: test.rb:9:1 13 | test.rb:(1,7)-(1,10) 14 | 15 | ## definition: test.rb:9:6 16 | test.rb:(2,8)-(2,10) 17 | 18 | ## definition: test.rb:9:13 19 | test.rb:(3,8)-(3,14) 20 | -------------------------------------------------------------------------------- /scenario/diagnostics/argumenterror.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(variable) 3 | end 4 | 5 | foo(1, 2) 6 | foo() 7 | 8 | ## diagnostics 9 | (4,0)-(4,3): wrong number of arguments (2 for 1) 10 | (5,0)-(5,3): wrong number of arguments (0 for 1) 11 | -------------------------------------------------------------------------------- /scenario/diagnostics/nomethoderror.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | foo 3 | 4 | ## diagnostics 5 | (1,0)-(1,3): undefined method: Object#foo 6 | -------------------------------------------------------------------------------- /scenario/diagnostics/reuse.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | unknown 4 | end 5 | 6 | ## diagnostics 7 | (2,2)-(2,9): undefined method: Object#unknown 8 | 9 | ## update 10 | def foo 11 | # line added 12 | unknown 13 | end 14 | 15 | ## diagnostics 16 | (3,4)-(3,11): undefined method: Object#unknown 17 | -------------------------------------------------------------------------------- /scenario/flow/is_a.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def test(x) 3 | if x.is_a?(Integer) 4 | x.foo # 3 5 | else 6 | x.bar # 5 7 | end 8 | end 9 | 10 | test(1) 11 | test("str") 12 | 13 | ## diagnostics 14 | (3,6)-(3,9): undefined method: Integer#foo 15 | (5,6)-(5,9): undefined method: String#bar 16 | 17 | ## update 18 | class C 19 | class D 20 | end 21 | 22 | def foo(n) 23 | if n.is_a?(D) 24 | n 25 | else 26 | "str" 27 | end 28 | end 29 | end 30 | 31 | C.new.foo(C::D.new) 32 | C.new.foo(1) 33 | 34 | ## assert 35 | class C 36 | class C::D 37 | end 38 | def foo: (C::D | Integer) -> (C::D | String) 39 | end 40 | -------------------------------------------------------------------------------- /scenario/flow/is_a2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | end 4 | 5 | class D 6 | def foo(n) 7 | if n.is_a?(C) 8 | n 9 | else 10 | "str" 11 | end 12 | end 13 | end 14 | 15 | D.new.foo(C.new) 16 | 17 | ## assert: test0.rb 18 | class C 19 | end 20 | class D 21 | def foo: (C) -> (C | String) 22 | end 23 | 24 | ## update: test1.rb 25 | class D 26 | class C 27 | end 28 | end 29 | 30 | ## assert: test0.rb 31 | class C 32 | end 33 | class D 34 | def foo: (C) -> String 35 | end 36 | 37 | ## update: test1.rb 38 | class D 39 | end 40 | " 41 | class A::C 42 | X = 1 43 | end 44 | " 45 | 46 | ## assert: test0.rb 47 | class C 48 | end 49 | class D 50 | def foo: (C) -> (C | String) 51 | end 52 | -------------------------------------------------------------------------------- /scenario/flow/is_a_module.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module M 3 | def m_method = :MMM 4 | end 5 | 6 | class C 7 | include M 8 | def c_method = :CCC 9 | end 10 | 11 | class D 12 | def d_method = :DDD 13 | end 14 | 15 | def foo(x) 16 | if x.is_a?(M) 17 | [x.m_method, x.c_method] 18 | else 19 | x.d_method 20 | end 21 | end 22 | 23 | foo(C.new) 24 | foo(D.new) 25 | 26 | ## diagnostics 27 | ## assert 28 | module M 29 | def m_method: -> :MMM 30 | end 31 | class C 32 | include M 33 | def c_method: -> :CCC 34 | end 35 | class D 36 | def d_method: -> :DDD 37 | end 38 | class Object 39 | def foo: (C | D) -> (:DDD | [:MMM, :CCC]) 40 | end 41 | -------------------------------------------------------------------------------- /scenario/flow/ivar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def initialize 4 | @var = nil 5 | end 6 | 7 | def set_var 8 | @var = 42 9 | end 10 | 11 | def run 12 | if @var 13 | @var.foo 14 | end 15 | end 16 | end 17 | 18 | ## diagnostics 19 | (12,11)-(12,14): undefined method: Integer#foo 20 | -------------------------------------------------------------------------------- /scenario/flow/nil.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | if n 4 | x = n 5 | else 6 | x = "str" 7 | end 8 | x 9 | end 10 | 11 | foo(1) 12 | foo(nil) 13 | 14 | ## assert 15 | class Object 16 | def foo: (Integer?) -> (Integer | String) 17 | end 18 | -------------------------------------------------------------------------------- /scenario/flow/nil2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | n = 1 unless n 4 | n 5 | end 6 | 7 | foo(1) 8 | foo(nil) 9 | 10 | ## assert 11 | class Object 12 | def foo: (Integer?) -> Integer 13 | end 14 | -------------------------------------------------------------------------------- /scenario/flow/or.rb: -------------------------------------------------------------------------------- 1 | ## update: tset.rbs 2 | class Object 3 | def int_or_nil: -> Integer? 4 | end 5 | 6 | ## update: test.rb 7 | def test 8 | int_or_nil || raise 9 | end 10 | 11 | ## assert 12 | class Object 13 | def test: -> Integer 14 | end 15 | -------------------------------------------------------------------------------- /scenario/flow/return_if.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | return unless n.is_a?(Integer) 4 | # n : Integer 5 | n.boo 6 | end 7 | 8 | foo(1) 9 | foo("str") 10 | 11 | ## diagnostics 12 | (4,4)-(4,7): undefined method: Integer#boo 13 | 14 | ## update 15 | def foo(n) 16 | raise unless n.is_a?(Integer) 17 | # n : Integer 18 | n.boo 19 | end 20 | 21 | foo(1) 22 | foo("str") 23 | 24 | ## diagnostics 25 | (4,4)-(4,7): undefined method: Integer#boo 26 | -------------------------------------------------------------------------------- /scenario/flow/while.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def test(x) 3 | while x 4 | x + 1 5 | end 6 | x 7 | end 8 | 9 | test(nil) 10 | test(1) 11 | 12 | ## assert 13 | class Object 14 | def test: (Integer?) -> nil 15 | end 16 | 17 | ## diagnostics 18 | -------------------------------------------------------------------------------- /scenario/hash/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | { 4 | a: 1, 5 | b: "str", 6 | } 7 | end 8 | 9 | def bar 10 | foo[:a] 11 | end 12 | 13 | def baz 14 | foo[:c] = 1.0 15 | foo[:c] 16 | end 17 | 18 | ## assert 19 | class Object 20 | def foo: -> Hash[:a | :b, Float | Integer | String] 21 | def bar: -> Integer 22 | def baz: -> (Float | Integer | String) 23 | end 24 | -------------------------------------------------------------------------------- /scenario/hash/hash-splat.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | { **bar, b: 1 } 4 | end 5 | 6 | def bar 7 | { a: 1 } 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> Hash[:a | :b, Integer] 13 | def bar: -> Hash[:a, Integer] 14 | end 15 | -------------------------------------------------------------------------------- /scenario/hash/implicit.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def create 3 | x = 1 4 | y = "str" 5 | { x:, y: } 6 | end 7 | 8 | ## assert 9 | class Object 10 | def create: -> Hash[:x | :y, Integer | String] 11 | end 12 | -------------------------------------------------------------------------------- /scenario/incremental/add-included-module.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | module M 3 | end 4 | 5 | def foo 6 | M::A.new(1) 7 | end 8 | ## update: test0.rb 9 | module M 10 | end 11 | 12 | def foo 13 | M::A.new(1) 14 | end 15 | 16 | ## update: test1.rb 17 | module M 18 | class A 19 | def initialize(n) 20 | end 21 | end 22 | end 23 | 24 | ## update: test1.rb 25 | module M 26 | class A 27 | def initialize(n) 28 | end 29 | end 30 | end 31 | 32 | ## assert: test1.rb 33 | module M 34 | class M::A 35 | def initialize: (Integer) -> nil 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /scenario/incremental/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | def foo(x) 3 | x * x 4 | end 5 | 6 | ## assert: test0.rb 7 | class Object 8 | def foo: (untyped) -> untyped 9 | end 10 | 11 | ## update: test1.rb 12 | def main 13 | foo(1) 14 | end 15 | 16 | ## assert: test0.rb 17 | class Object 18 | def foo: (Integer) -> Integer 19 | end 20 | 21 | ## update: test1.rb 22 | def main 23 | foo("str") 24 | end 25 | 26 | ## assert: test0.rb 27 | class Object 28 | def foo: (String) -> String 29 | end 30 | 31 | ## diagnostics: test0.rb 32 | (2,4)-(2,5): wrong type of arguments 33 | -------------------------------------------------------------------------------- /scenario/incremental/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | x + 1 4 | end 5 | 6 | def main 7 | foo(2) 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: (Integer) -> Integer 13 | def main: -> Integer 14 | end 15 | 16 | ## update 17 | def foo(x) 18 | x + 1.0 19 | end 20 | 21 | def main 22 | foo(2) 23 | end 24 | 25 | ## assert 26 | class Object 27 | def foo: (Integer) -> Float 28 | def main: -> Float 29 | end 30 | -------------------------------------------------------------------------------- /scenario/incremental/basic3.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | x + 1 4 | end 5 | 6 | def main 7 | foo(2) 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: (Integer) -> Integer 13 | def main: -> Integer 14 | end 15 | 16 | ## update 17 | def foo(x) 18 | x + 1 19 | end 20 | 21 | def main 22 | foo("str") 23 | end 24 | 25 | ## assert 26 | class Object 27 | def foo: (String) -> String 28 | def main: -> String 29 | end 30 | -------------------------------------------------------------------------------- /scenario/incremental/basic4.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def foo(n) 4 | C 5 | end 6 | end 7 | 8 | ## assert 9 | class C 10 | def foo: (untyped) -> singleton(C) 11 | end 12 | 13 | ## update 14 | class C 15 | class C 16 | end 17 | 18 | def foo(n) 19 | C 20 | end 21 | end 22 | 23 | ## assert 24 | class C 25 | class C::C 26 | end 27 | def foo: (untyped) -> singleton(C::C) 28 | end 29 | 30 | ## update 31 | class C 32 | class D 33 | end 34 | 35 | def foo(n) 36 | C 37 | end 38 | end 39 | 40 | ## assert 41 | class C 42 | class C::D 43 | end 44 | def foo: (untyped) -> singleton(C) 45 | end 46 | -------------------------------------------------------------------------------- /scenario/incremental/basic5.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | def foo(n, &b) 3 | b.call(1.0) 4 | end 5 | 6 | ## update: test1.rb 7 | def bar(_) 8 | foo(12) do |n| 9 | "str" 10 | end 11 | end 12 | 13 | def baz(_) 14 | foo(12) do |n| 15 | "str" 16 | end 17 | end 18 | 19 | ## assert_without_validation: test0.rb 20 | class Object 21 | def foo: (Integer) { (Float) -> String } -> String 22 | end 23 | 24 | ## update: test1.rb 25 | def bar(_) 26 | foo(12) do |n| 27 | 1 28 | end 29 | end 30 | 31 | def baz(_) 32 | foo(12) do |n| 33 | "str" 34 | end 35 | end 36 | 37 | ## assert_without_validation: test0.rb 38 | class Object 39 | def foo: (Integer) { (Float) -> (Integer | String) } -> (Integer | String) 40 | end 41 | 42 | ## update: test1.rb 43 | def bar(_) 44 | foo(12) do |n| 45 | 1 46 | end 47 | end 48 | 49 | def baz(_) 50 | foo(12) do |n| 51 | 1 52 | end 53 | end 54 | 55 | ## assert_without_validation: test0.rb 56 | class Object 57 | def foo: (Integer) { (Float) -> Integer } -> Integer 58 | end 59 | -------------------------------------------------------------------------------- /scenario/incremental/change-included-module.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | module M 3 | def foo(n) 4 | end 5 | end 6 | 7 | class C 8 | include M 9 | end 10 | 11 | C.new.foo(1) 12 | 13 | ## assert: test0.rb 14 | module M 15 | def foo: (Integer) -> nil 16 | end 17 | class C 18 | include M 19 | end 20 | 21 | ## update: test1.rb 22 | class C 23 | module M 24 | def foo(n) 25 | end 26 | end 27 | end 28 | 29 | ## assert: test0.rb 30 | module M 31 | def foo: (untyped) -> nil 32 | end 33 | class C 34 | include C::M 35 | end 36 | 37 | ## assert: test1.rb 38 | class C 39 | module C::M 40 | def foo: (Integer) -> nil 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /scenario/incremental/change-superclass.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | def target(n) = n 4 | end 5 | class C2 6 | def target(n) = n 7 | end 8 | 9 | class X 10 | class D < C 11 | # This invokes C#target 12 | def foo = target(1) 13 | end 14 | end 15 | 16 | ## assert: test0.rb 17 | class C 18 | def target: (Integer) -> Integer 19 | end 20 | class C2 21 | def target: (untyped) -> untyped 22 | end 23 | class X 24 | class X::D < C 25 | def foo: -> Integer 26 | end 27 | end 28 | 29 | ## update: test1.rb 30 | class X 31 | # This class definition changes the superclass of D, and 32 | # also changes the call to "target" will invoke C2#target 33 | class C < C2 34 | end 35 | end 36 | 37 | ## assert: test0.rb 38 | class C 39 | def target: (untyped) -> untyped 40 | end 41 | class C2 42 | def target: (Integer) -> Integer 43 | end 44 | class X 45 | class X::D < X::C 46 | def foo: -> Integer 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /scenario/incremental/remove-included-module2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | module M 3 | def foo(n) 4 | end 5 | end 6 | 7 | C.new.foo(1) 8 | 9 | ## update: test1.rb 10 | class C 11 | include M 12 | end 13 | 14 | ## assert: test0.rb 15 | module M 16 | def foo: (Integer) -> nil 17 | end 18 | 19 | ## update: test1.rb 20 | class C 21 | end 22 | 23 | ## assert: test0.rb 24 | module M 25 | def foo: (untyped) -> nil 26 | end 27 | -------------------------------------------------------------------------------- /scenario/known-issues/alias-global-variable.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | $v = :ok 4 | end 5 | 6 | def bar 7 | alias $new_v $v 8 | $new_v 9 | end 10 | 11 | ## assert 12 | class Object 13 | def foo: -> :ok 14 | def bar: -> :ok 15 | end 16 | -------------------------------------------------------------------------------- /scenario/known-issues/array-zip-type.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | [1].zip(["str"]) do |x, y| 4 | return x 5 | end 6 | nil 7 | end 8 | 9 | ## assert 10 | class Object 11 | def foo: -> Integer? 12 | end 13 | -------------------------------------------------------------------------------- /scenario/known-issues/block_optionals.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def test_yield 3 | yield 1, 2 4 | end 5 | 6 | def check1 7 | test_yield do |x, y = :y| 8 | return [x, y] 9 | end 10 | nil 11 | end 12 | 13 | def check2 14 | test_yield do |x, y, z = :z| 15 | return [x, y, z] 16 | end 17 | nil 18 | end 19 | 20 | # test_yield do |x, kw: 1| 21 | # etc. 22 | 23 | ## assert 24 | class Object 25 | def test_yield: { (Integer, Integer) -> bot } -> bot 26 | def check1: -> [Integer, Integer]? 27 | def check2: -> [Integer, Integer, :z]? 28 | end 29 | -------------------------------------------------------------------------------- /scenario/known-issues/break-in-loop.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def bar 3 | yield 4 | nil 5 | end 6 | 7 | def foo 8 | bar do 9 | break :a 10 | until true 11 | break :b 12 | end 13 | break :c 14 | end 15 | end 16 | 17 | ## assert: test.rb 18 | class Object 19 | def bar: { () -> (:a | :c) } -> nil 20 | def foo: -> nil 21 | end 22 | 23 | ## update: test.rb 24 | def foo 25 | until true 26 | break :a 27 | end 28 | end 29 | 30 | ## assert: test.rb 31 | class Object 32 | def foo: -> :a 33 | end 34 | -------------------------------------------------------------------------------- /scenario/known-issues/cbase-is-not-class.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | Foo = 1 3 | 4 | class Foo::Bar # we want to warn that cbase is not a module 5 | end 6 | 7 | ## diagnostics 8 | -------------------------------------------------------------------------------- /scenario/known-issues/check-return-type.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: -> Foo 4 | def foo=: (Foo) -> Foo 5 | end 6 | 7 | ## update: test.rb 8 | class Foo 9 | def initialize 10 | @foo = 1 11 | end 12 | 13 | attr_accessor :foo 14 | end 15 | 16 | ## diagnostics: test.rb 17 | (6,2)-(6,20): expected: Foo; actual: (Foo | Integer) 18 | -------------------------------------------------------------------------------- /scenario/known-issues/const-scope.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | D = 1 4 | end 5 | 6 | ## assert 7 | class C 8 | D: Integer 9 | end 10 | -------------------------------------------------------------------------------- /scenario/known-issues/constant-path.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | module Baz 3 | module Foo 4 | class Bar < ::Foo::Bar 5 | end 6 | end 7 | end 8 | 9 | module Foo 10 | class Bar 11 | end 12 | end 13 | 14 | ## assert: test.rb 15 | module Baz 16 | module Foo 17 | class Bar < ::Foo::Bar 18 | end 19 | end 20 | end 21 | 22 | module Foo 23 | class Bar 24 | end 25 | end 26 | 27 | ## update: test.rb 28 | class Foo 29 | end 30 | 31 | module Bar 32 | class Foo < Foo 33 | end 34 | end 35 | 36 | ## assert: test.rb 37 | class Foo 38 | end 39 | 40 | module Bar 41 | class Foo < ::Foo 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /scenario/known-issues/dynamic-include.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | x = Module.new 4 | include x # should be warned 5 | include *[x] # should be warned 6 | end 7 | 8 | ## diagnostics 9 | should be warned 10 | -------------------------------------------------------------------------------- /scenario/known-issues/fcall-include.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def include(x) 4 | x 5 | end 6 | 7 | def check 8 | include(1) 9 | end 10 | end 11 | 12 | ## assert 13 | class C 14 | def include: (Integer) -> Integer 15 | def check: -> Integer 16 | end 17 | -------------------------------------------------------------------------------- /scenario/known-issues/forwarding-arguments.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(...) 3 | bar(...) 4 | end 5 | 6 | def bar(*a, **b) 7 | [a, b] 8 | end 9 | 10 | foo(1, x: 4, y: 5) 11 | 12 | ## assert 13 | class Object 14 | def foo: (*Integer, **Hash[:x | :y, Integer]) -> [Array[Integer], Hash[:x | :y, Integer]] 15 | def bar: (*Integer, **Hash[:x | :y, Integer]) -> [Array[Integer], Hash[:x | :y, Integer]] 16 | end 17 | -------------------------------------------------------------------------------- /scenario/known-issues/keywords.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(a) 3 | a 4 | end 5 | 6 | foo(x: 1) 7 | 8 | ## assert 9 | class Object 10 | def foo: (Hash[:x, Integer]) -> Hash[:x, Integer] 11 | end 12 | -------------------------------------------------------------------------------- /scenario/known-issues/multi-const-write.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | D = 1 4 | D = "str" 5 | end 6 | 7 | ## assert 8 | class C 9 | C::D: (Integer | String) 10 | end 11 | -------------------------------------------------------------------------------- /scenario/known-issues/multi_arg_break.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | 1.times do 4 | break :a, :b, :c 5 | end 6 | end 7 | 8 | # return :a, :b, :c 9 | # next :a, :b, :c 10 | # retry 11 | 12 | ## assert 13 | -------------------------------------------------------------------------------- /scenario/known-issues/multi_target_arg.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check(z, (x, y)) 3 | [z, y, x] 4 | end 5 | 6 | check(1, [1, "str"]) 7 | 8 | ## assert 9 | -------------------------------------------------------------------------------- /scenario/known-issues/multi_target_block_arg.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def yield_values 3 | yield 1, [1.0, "str"] 4 | end 5 | 6 | def check 7 | yield_values do |x, (y, z)| 8 | return [x, y, z] 9 | end 10 | nil 11 | end 12 | 13 | ## assert 14 | -------------------------------------------------------------------------------- /scenario/known-issues/optional-type-param.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Foo[X, Y = Integer] 3 | def initialize: (X) -> void 4 | end 5 | 6 | class Object 7 | def get_foo_str: -> _Foo[String] 8 | def accept_foo_str: (_Foo[String]) -> void 9 | end 10 | 11 | ## update: test.rb 12 | accept_foo_str(get_foo_st) 13 | 14 | ## assert 15 | -------------------------------------------------------------------------------- /scenario/known-issues/retry.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | n = 1 4 | begin 5 | raise if rand < 0.5 6 | n 7 | rescue 8 | n = "str" 9 | retry 10 | end 11 | end 12 | 13 | foo 14 | 15 | ## assert 16 | class Object 17 | def foo: () -> (Integer | String) 18 | end 19 | 20 | ## diagnostics 21 | -------------------------------------------------------------------------------- /scenario/known-issues/singleton-class.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | k = Time 3 | class << k 4 | def foo = :ok 5 | end 6 | 7 | ## assert 8 | class Time 9 | def self.foo: -> :ok 10 | end 11 | 12 | ## update 13 | class Foo 14 | class << self 15 | def self.bar = :ok 16 | end 17 | end 18 | 19 | ## assert 20 | class Foo 21 | end 22 | -------------------------------------------------------------------------------- /scenario/known-issues/singleton-method.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def Foo.foo = :ok 4 | s = "Foo" 5 | def (s).foo = :ok 6 | end 7 | 8 | def check 9 | Foo.foo 10 | end 11 | 12 | ## assert 13 | class Foo 14 | def self.foo: -> :ok 15 | def self.???foo: -> :ok 16 | end 17 | class Object 18 | def check: -> :ok 19 | end 20 | -------------------------------------------------------------------------------- /scenario/known-issues/splat-on-non-array.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | a = *123 # this calls `to_a` on 123, but the error should be suppressed 4 | end 5 | 6 | ## diagnostics 7 | -------------------------------------------------------------------------------- /scenario/known-issues/struct.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | Foo = Struct.new(:foo) do 3 | def foo? 4 | !!foo 5 | end 6 | 7 | private 8 | 9 | def not_foo? 10 | !foo 11 | end 12 | end 13 | 14 | ## assert: test.rb 15 | class Foo < Struct[untyped] 16 | def foo: -> untyped 17 | def foo?: -> bool 18 | private 19 | def not_foo?: -> bool 20 | end 21 | -------------------------------------------------------------------------------- /scenario/known-issues/unsupported-arg.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: (String) -> String 4 | | (Integer) -> Integer 5 | def get1: -> (String | Integer) 6 | def get2: -> (String | Integer | nil) 7 | end 8 | 9 | ## update: test.rb 10 | def check1 = foo(get1) 11 | def check2 = foo(get2) 12 | 13 | ## diagnostics 14 | (2,13)-(2,16): expected: (String | Integer); actual: (String | Integer)? 15 | -------------------------------------------------------------------------------- /scenario/lambda/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | -> () { 1 } 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> Proc 9 | end 10 | 11 | ## update 12 | def foo 13 | b = -> () { 1 } 14 | b.() 15 | end 16 | 17 | ## assert 18 | class Object 19 | def foo: -> untyped 20 | end 21 | -------------------------------------------------------------------------------- /scenario/meta/attr_accessor.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | attr_accessor :x 4 | 5 | def foo 6 | x 7 | end 8 | end 9 | 10 | foo = Foo.new 11 | foo.x = "str" 12 | 13 | ## assert 14 | class Foo 15 | def x: -> String 16 | def x=: (String) -> String 17 | def foo: -> String 18 | end 19 | -------------------------------------------------------------------------------- /scenario/meta/attr_reader.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class Foo 3 | def initialize(x, y) 4 | @x = x 5 | @y = y 6 | end 7 | 8 | def foo 9 | x 10 | end 11 | 12 | attr_reader :x, :y 13 | end 14 | 15 | ## assert: test0.rb 16 | class Foo 17 | def initialize: (untyped, untyped) -> untyped 18 | def foo: -> untyped 19 | def x: -> untyped 20 | def y: -> untyped 21 | end 22 | 23 | ## update: test1.rb 24 | Foo.new(1, 1.0) 25 | 26 | ## assert: test0.rb 27 | class Foo 28 | def initialize: (Integer, Float) -> Float 29 | def foo: -> Integer 30 | def x: -> Integer 31 | def y: -> Float 32 | end 33 | 34 | ## update: test1.rb 35 | Foo.new(1.0, 1) 36 | 37 | ## assert: test0.rb 38 | class Foo 39 | def initialize: (Float, Integer) -> Integer 40 | def foo: -> Float 41 | def x: -> Float 42 | def y: -> Integer 43 | end 44 | -------------------------------------------------------------------------------- /scenario/method/alias.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo(n) 4 | n 5 | end 6 | 7 | alias :bar :foo 8 | end 9 | 10 | Foo.new.bar(1) 11 | 12 | ## assert 13 | class Foo 14 | def foo: (Integer) -> Integer 15 | end 16 | -------------------------------------------------------------------------------- /scenario/method/attrasgn.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def foo=(x) 4 | @foo = x 5 | end 6 | 7 | def foo 8 | @foo 9 | end 10 | end 11 | 12 | f = C.new 13 | f.foo = 42 14 | 15 | ## assert 16 | class C 17 | def foo=: (Integer) -> Integer 18 | def foo: -> Integer 19 | end 20 | -------------------------------------------------------------------------------- /scenario/method/block-arg.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&blk) 3 | 1 + blk 4 | end 5 | 6 | ## diagnostics 7 | (2,4)-(2,5): failed to resolve overloads 8 | -------------------------------------------------------------------------------- /scenario/method/change-number-of-arguments.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def bar(x) 3 | end 4 | 5 | def foo(x, y) 6 | bar() 7 | end 8 | 9 | foo(1, 2) 10 | 11 | ## assert 12 | class Object 13 | def bar: (untyped) -> nil 14 | def foo: (Integer, Integer) -> untyped 15 | end 16 | 17 | ## update 18 | def bar(x) 19 | end 20 | 21 | def foo(x, y) 22 | bar(x) 23 | end 24 | 25 | foo(1, 2) 26 | 27 | ## assert 28 | class Object 29 | def bar: (Integer) -> nil 30 | def foo: (Integer, Integer) -> nil 31 | end 32 | 33 | ## update 34 | def bar(x) 35 | end 36 | 37 | def foo(x, y) 38 | bar(x, y) 39 | end 40 | 41 | foo(1, 2) 42 | 43 | ## assert 44 | class Object 45 | def bar: (untyped) -> nil 46 | def foo: (Integer, Integer) -> untyped 47 | end 48 | 49 | ## update 50 | def bar(x) 51 | end 52 | 53 | def foo(x, y) 54 | bar(x) 55 | end 56 | 57 | foo(1, 2) 58 | 59 | ## assert 60 | class Object 61 | def bar: (Integer) -> nil 62 | def foo: (Integer, Integer) -> nil 63 | end 64 | -------------------------------------------------------------------------------- /scenario/method/empty_def.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | end 4 | 5 | foo(1) 6 | 7 | ## assert 8 | class Object 9 | def foo: (Integer) -> nil 10 | end 11 | -------------------------------------------------------------------------------- /scenario/method/function.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | n 4 | end 5 | 6 | class Foo 7 | def bar 8 | foo(1) 9 | end 10 | end 11 | 12 | ## assert 13 | class Object 14 | def foo: (Integer) -> Integer 15 | end 16 | class Foo 17 | def bar: -> Integer 18 | end 19 | -------------------------------------------------------------------------------- /scenario/method/keywords.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x:) 3 | x 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: (x: untyped) -> untyped 9 | end 10 | 11 | ## update 12 | def foo(x: 1) 13 | x 14 | end 15 | 16 | ## assert 17 | class Object 18 | def foo: (?x: Integer) -> Integer 19 | end 20 | 21 | ## update 22 | def foo(x: 1, y:) 23 | x 24 | end 25 | 26 | ## assert 27 | class Object 28 | def foo: (y: untyped, ?x: Integer) -> Integer 29 | end 30 | 31 | ## update 32 | def foo(**kw) 33 | kw 34 | end 35 | 36 | ## assert 37 | class Object 38 | def foo: (**untyped) -> untyped 39 | end 40 | 41 | ## update 42 | def foo(x:) 43 | x 44 | end 45 | 46 | foo(x: "str") 47 | 48 | ## assert 49 | class Object 50 | def foo: (x: String) -> String 51 | end 52 | 53 | ## update 54 | def foo(x: 1) 55 | x 56 | end 57 | 58 | foo(x: "str") 59 | 60 | ## assert 61 | class Object 62 | def foo: (?x: Integer | String) -> (Integer | String) 63 | end 64 | 65 | ## update 66 | def foo(a:, b: 1, **c) 67 | c 68 | end 69 | 70 | foo(a: '', b: 1, c: true) 71 | 72 | ## assert 73 | class Object 74 | def foo: (a: String, ?b: Integer, **Hash[:a | :b | :c, Integer | String | true]) -> Hash[:a | :b | :c, Integer | String | true] 75 | end 76 | -------------------------------------------------------------------------------- /scenario/method/mid_code_range.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def bar(x) 3 | end 4 | 5 | def foo(x, y) 6 | bar() 7 | end 8 | 9 | foo(1, 2) 10 | 11 | ## assert 12 | class Object 13 | def bar: (untyped) -> nil 14 | def foo: (Integer, Integer) -> untyped 15 | end 16 | 17 | ## update 18 | def foo(x) 19 | end 20 | 21 | foo(1, 2) 22 | self.foo(1, 2) 23 | 24 | ## diagnostics 25 | (4,0)-(4,3): wrong number of arguments (2 for 1) 26 | (5,5)-(5,8): wrong number of arguments (2 for 1) 27 | -------------------------------------------------------------------------------- /scenario/method/multi_args.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def initialize(x, y, z) 4 | @x = x 5 | @y = y 6 | @z = z 7 | end 8 | end 9 | 10 | Foo.new(1, 1.0, "String") 11 | 12 | ## assert 13 | class Foo 14 | def initialize: (Integer, Float, String) -> String 15 | end 16 | -------------------------------------------------------------------------------- /scenario/method/no_args.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | 1 4 | end 5 | 6 | def bar 7 | foo 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> Integer 13 | def bar: -> Integer 14 | end 15 | -------------------------------------------------------------------------------- /scenario/method/prevent-reuse.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | ary = 4 | def foo 5 | end 6 | end 7 | 8 | ## update: test.rb 9 | class Foo 10 | ary = 11 | def foo 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /scenario/method/rbs_alias.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | 1.0.phase 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> (Float | Integer) 9 | end 10 | -------------------------------------------------------------------------------- /scenario/method/reuse-alias.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def bar(n) 4 | end 5 | 6 | def test 7 | alias foo bar # This alias is reused 8 | foo(1) 9 | end 10 | end 11 | 12 | ## update 13 | class C 14 | def bar(n) 15 | end 16 | 17 | def test 18 | alias foo bar # This alias is reused 19 | foo(1) 20 | end 21 | end 22 | 23 | ## update 24 | class C 25 | def bar(n) 26 | end 27 | 28 | def test 29 | # The alias was removed 30 | foo(1) 31 | end 32 | end 33 | 34 | ## assert 35 | class C 36 | def bar: (untyped) -> nil 37 | def test: -> untyped 38 | end 39 | -------------------------------------------------------------------------------- /scenario/method/safe-navigation.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def return_optional 3 | if rand < 0.5 4 | "str" 5 | else 6 | nil 7 | end 8 | end 9 | 10 | def check 11 | return_optional&.to_i 12 | end 13 | 14 | ## diagnostics 15 | 16 | ## assert 17 | class Object 18 | def return_optional: -> String? 19 | def check: -> Integer? 20 | end 21 | -------------------------------------------------------------------------------- /scenario/method/self-alias.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def foo 4 | foo 5 | 1 6 | end 7 | 8 | alias foo foo 9 | end 10 | 11 | ## assert 12 | class C 13 | def foo: -> Integer 14 | end 15 | 16 | ## update 17 | class C 18 | def foo 19 | foo 20 | 42 21 | end 22 | alias foo bar 23 | alias bar foo 24 | end 25 | 26 | ## assert 27 | class C 28 | def foo: -> Integer 29 | end 30 | 31 | ## update 32 | class C 33 | def bar 34 | foo 35 | 42 36 | end 37 | alias foo bar 38 | alias bar foo 39 | end 40 | 41 | ## assert 42 | class C 43 | def bar: -> Integer 44 | end 45 | 46 | ## update 47 | class C 48 | alias foo bar 49 | alias bar foo 50 | end 51 | 52 | C.new.foo 53 | 54 | ## assert 55 | class C 56 | end 57 | -------------------------------------------------------------------------------- /scenario/method/singleton.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def self.foo 4 | 1 5 | end 6 | 7 | def self.bar 8 | foo 9 | end 10 | end 11 | 12 | def test 13 | Foo.foo 14 | end 15 | 16 | ## assert 17 | class Foo 18 | def self.foo: -> Integer 19 | def self.bar: -> Integer 20 | end 21 | class Object 22 | def test: -> Integer 23 | end 24 | -------------------------------------------------------------------------------- /scenario/method/splat-arg.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def rest(*args) 4 | args 5 | end 6 | 7 | def call_rest_method 8 | rest(1) 9 | end 10 | end 11 | 12 | ## assert 13 | class Foo 14 | def rest: (*Integer) -> Array[Integer] 15 | def call_rest_method: -> Array[Integer] 16 | end 17 | -------------------------------------------------------------------------------- /scenario/method/subclass-methods.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | def foo 4 | bar(1) # should call all subclass methods 5 | end 6 | end 7 | 8 | class D < C 9 | end 10 | 11 | ## update: test1.rb 12 | 13 | class D < C 14 | def bar(n) 15 | end 16 | end 17 | 18 | ## assert 19 | class D < C 20 | def bar: (Integer) -> nil 21 | end 22 | -------------------------------------------------------------------------------- /scenario/method/undef.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo 4 | 42 5 | end 6 | 7 | # Currently, TypeProf just ignores undef statements 8 | undef foo 9 | undef :foo, :bar 10 | undef :"foo#{ 42 }" 11 | end 12 | 13 | ## assert 14 | class Foo 15 | def foo: -> Integer 16 | end 17 | -------------------------------------------------------------------------------- /scenario/misc/alias_gvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | alias $a $b # Not implemented yet; just ignored 3 | 4 | ## assert 5 | -------------------------------------------------------------------------------- /scenario/misc/argv.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(n) 3 | n.to_s 4 | end 5 | 6 | foo(ARGV[0].to_i) 7 | 8 | ## assert 9 | class Object 10 | def foo: (Integer) -> String 11 | end 12 | -------------------------------------------------------------------------------- /scenario/misc/ast_glitch.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | {} 4 | # RubyVM::AST.parse returns "nil" instead of neither NODE_NIL or NODE_RETURN 5 | return nil 6 | end 7 | 8 | ## assert 9 | class Object 10 | def foo: -> nil 11 | end 12 | -------------------------------------------------------------------------------- /scenario/misc/ast_glitch2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo 4 | end 5 | end 6 | 7 | ## update 8 | class Foo < 9 | def foo 10 | end 11 | end 12 | 13 | ## update 14 | class Foo << 15 | def foo 16 | end 17 | end 18 | 19 | ## update 20 | class Foo < 21 | def foo 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /scenario/misc/bot-diagnostics.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | raise.foo 3 | 4 | ## diagnostics 5 | -------------------------------------------------------------------------------- /scenario/misc/class_method.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def self_class 3 | self.class 4 | end 5 | 6 | def int_class 7 | 1.class 8 | end 9 | 10 | def array_class 11 | [1].class 12 | end 13 | 14 | def hash_class 15 | { 1 => "str" }.class 16 | end 17 | 18 | def class_class 19 | Object.class 20 | end 21 | 22 | def unknown_class(x) 23 | x.class 24 | end 25 | 26 | ## assert 27 | class Object 28 | def self_class: -> singleton(Object) 29 | def int_class: -> singleton(Integer) 30 | def array_class: -> singleton(Array) 31 | def hash_class: -> singleton(Hash) 32 | def class_class: -> singleton(Class) 33 | def unknown_class: (untyped) -> untyped 34 | end 35 | -------------------------------------------------------------------------------- /scenario/misc/complex.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | 1i 4 | end 5 | 6 | ## assert 7 | class Object 8 | def check: -> Complex 9 | end 10 | -------------------------------------------------------------------------------- /scenario/misc/define_method_return.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | define_method(:foo) { return } 4 | end 5 | 6 | ## assert 7 | class Foo 8 | end 9 | -------------------------------------------------------------------------------- /scenario/misc/defined.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | if defined?($x) 4 | 1 5 | else 6 | "str" 7 | end 8 | end 9 | 10 | ## assert 11 | class Object 12 | def foo: -> (Integer | String) 13 | end 14 | -------------------------------------------------------------------------------- /scenario/misc/dstr.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | "foo#{ bar(1) }" 4 | "foo"\ 5 | "#{ bar(1) }" 6 | "foo#{ bar(1) }baz#{ qux(1.0) }" 7 | end 8 | 9 | def bar(n) 10 | "bar" 11 | end 12 | 13 | def qux(n) 14 | "qux" 15 | end 16 | 17 | ## assert 18 | class Object 19 | def foo: -> String 20 | def bar: (Integer) -> String 21 | def qux: (Float) -> String 22 | end 23 | 24 | ## update 25 | def foo 26 | "foo#{ }" 27 | end 28 | 29 | ## assert 30 | class Object 31 | def foo: -> String 32 | end 33 | 34 | ## update 35 | def xstring_lit(n) 36 | `echo foo` 37 | end 38 | 39 | def interpolate_xstring 40 | `echo #{xstring_lit(10)}` 41 | end 42 | 43 | ## assert 44 | class Object 45 | def xstring_lit: (Integer) -> String 46 | def interpolate_xstring: -> String 47 | end 48 | 49 | ## update 50 | def foo 51 | "#$1" 52 | end 53 | 54 | ## assert 55 | class Object 56 | def foo: -> String 57 | end 58 | -------------------------------------------------------------------------------- /scenario/misc/dsym.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def foo = "symbol#{ 42 }" 3 | 4 | ## assert: test.rb 5 | class Object 6 | def foo: -> String 7 | end 8 | 9 | ## update: test.rb 10 | def foo = :"symbol#{ 42 }" 11 | 12 | ## assert: test.rb 13 | class Object 14 | def foo: -> Symbol 15 | end -------------------------------------------------------------------------------- /scenario/misc/fcall-for-subclass-methods.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def run(n) 4 | run0(n) 5 | end 6 | 7 | def run0(_) 8 | raise "abstract method" 9 | end 10 | end 11 | 12 | class D < C 13 | def run0(n) 14 | end 15 | end 16 | 17 | C.new.run(1) 18 | 19 | ## assert 20 | class C 21 | def run: (Integer) -> nil 22 | def run0: (Integer) -> bot 23 | end 24 | class D < C 25 | def run0: (Integer) -> nil 26 | end 27 | -------------------------------------------------------------------------------- /scenario/misc/flip_flop.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | n = 3 4 | if (n==2)..(n==2) 5 | # flip_flop_node can not become a return value because it is only available in condition. 6 | end 7 | end 8 | 9 | ## assert 10 | class Object 11 | def foo: -> nil 12 | end -------------------------------------------------------------------------------- /scenario/misc/for.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | for i in 1..100 4 | # currently, TypeProf does not initialize i 5 | return 1 6 | end 7 | end 8 | 9 | def bar 10 | for i in 1..100 11 | return 1 12 | end 13 | end 14 | 15 | ## assert 16 | class Object 17 | def foo: -> Integer? 18 | def bar: -> Integer? 19 | end 20 | -------------------------------------------------------------------------------- /scenario/misc/is_a.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class C 3 | def foo(x) 4 | x.is_a?(self.class) 5 | end 6 | end 7 | 8 | C.new.foo(1) 9 | -------------------------------------------------------------------------------- /scenario/misc/match_asgn.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | if /(?foo)/ =~ "foo" 4 | a 5 | else 6 | 1 7 | end 8 | end 9 | 10 | ## assert 11 | class Object 12 | def check: -> (Integer | String) 13 | end 14 | -------------------------------------------------------------------------------- /scenario/misc/mix-const.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | end 4 | 5 | ## update 6 | C = 1 7 | def foo 8 | C 9 | end 10 | 11 | ## assert 12 | C: Integer 13 | class Object 14 | def foo: -> Integer 15 | end 16 | -------------------------------------------------------------------------------- /scenario/misc/op_asgn1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | ary = [0] 4 | ary[0] ||= "str" 5 | ary 6 | end 7 | 8 | ## assert 9 | class Object 10 | def foo: -> [Integer | String] 11 | end 12 | -------------------------------------------------------------------------------- /scenario/misc/op_asgn_or.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | $x 4 | end 5 | 6 | $x ||= 1 7 | $x ||= "str" 8 | 9 | ## assert 10 | class Object 11 | def foo: -> (Integer | String) 12 | end 13 | -------------------------------------------------------------------------------- /scenario/misc/post-exec.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check(x) 3 | end 4 | 5 | def foo 6 | x = 1 7 | END { check(x) } 8 | x = "str" 9 | end 10 | 11 | ## assert 12 | class Object 13 | def check: (String) -> nil 14 | def foo: -> String 15 | end 16 | -------------------------------------------------------------------------------- /scenario/misc/proc.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: (^(Integer) -> void) -> void 4 | end 5 | 6 | ## update: test.rb 7 | def check(x) 8 | end 9 | f = ->(x) { check(x) } # TODO: this should pass an Integer to the method "check"? Is it possible? 10 | foo(f) 11 | 12 | ## assert 13 | class Object 14 | def check: (untyped) -> nil 15 | end 16 | -------------------------------------------------------------------------------- /scenario/misc/range.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | 0..1 4 | end 5 | def bar 6 | 0.. 7 | end 8 | def baz 9 | ..1 10 | end 11 | def qux 12 | nil..nil 13 | end 14 | 15 | ## assert 16 | class Object 17 | def foo: -> Range[Integer] 18 | def bar: -> Range[Integer?] 19 | def baz: -> Range[Integer?] 20 | def qux: -> Range[nil] 21 | end 22 | -------------------------------------------------------------------------------- /scenario/misc/rational.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | 1r 4 | end 5 | 6 | ## assert 7 | class Object 8 | def check: -> Rational 9 | end 10 | -------------------------------------------------------------------------------- /scenario/misc/regexp.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check1 3 | /foo/ 4 | end 5 | def check2 6 | /foo#{ 1 }bar/ 7 | end 8 | def check3 9 | if /foo/ 10 | :then 11 | else 12 | :else 13 | end 14 | end 15 | def check4 16 | if /foo#{ 1 }/ 17 | :then 18 | else 19 | :else 20 | end 21 | end 22 | 23 | ## assert 24 | class Object 25 | def check1: -> Regexp 26 | def check2: -> Regexp 27 | def check3: -> (:else | :then) 28 | def check4: -> (:else | :then) 29 | end 30 | -------------------------------------------------------------------------------- /scenario/misc/set.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | s = Set[] 4 | s << 42 # special handling of Set#<< is not implemented 5 | s 6 | end 7 | 8 | ## assert 9 | class Object 10 | def foo: -> Set[Integer] 11 | end 12 | -------------------------------------------------------------------------------- /scenario/misc/source_encoding.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | __ENCODING__ 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> Encoding 9 | end 10 | -------------------------------------------------------------------------------- /scenario/misc/source_file.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | __FILE__ 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> String 9 | end 10 | -------------------------------------------------------------------------------- /scenario/misc/source_line.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | __LINE__ 4 | end 5 | 6 | ## assert 7 | class Object 8 | def foo: -> Integer 9 | end 10 | -------------------------------------------------------------------------------- /scenario/misc/stmts_diff.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def foo 3 | end 4 | 5 | foo 6 | 7 | ## update: test.rb 8 | def foo 9 | end 10 | 11 | def foo # This is a new node (should have no prev_node) 12 | end 13 | 14 | foo 15 | 16 | ## assert: test.rb 17 | class Object 18 | def foo: -> nil 19 | def foo: -> nil 20 | end 21 | -------------------------------------------------------------------------------- /scenario/misc/super-with-alias.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def foo 4 | 42 5 | end 6 | end 7 | 8 | class D < C 9 | alias bar foo 10 | end 11 | 12 | class E < D 13 | def bar 14 | super 15 | end 16 | end 17 | 18 | ## assert 19 | class C 20 | def foo: -> Integer 21 | end 22 | class D < C 23 | end 24 | class E < D 25 | def bar: -> Integer 26 | end 27 | -------------------------------------------------------------------------------- /scenario/misc/super.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (Integer) -> :int 4 | | (String) -> :str 5 | end 6 | 7 | ## update: test.rb 8 | class D1 < C 9 | def foo 10 | super(1) 11 | end 12 | end 13 | 14 | class D2 < C 15 | def foo 16 | super("str") 17 | end 18 | end 19 | 20 | ## assert 21 | class D1 < C 22 | def foo: -> :int 23 | end 24 | class D2 < C 25 | def foo: -> :str 26 | end 27 | 28 | ## update 29 | class StringifyKeyHash < Hash 30 | def [](key) 31 | super(key.to_s) 32 | end 33 | end 34 | 35 | ## assert 36 | class StringifyKeyHash < Hash 37 | def []: (untyped) -> untyped 38 | end 39 | -------------------------------------------------------------------------------- /scenario/misc/toplevel-return.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | return 3 | return 1 4 | return "foo" 5 | 6 | ## assert 7 | -------------------------------------------------------------------------------- /scenario/patterns/alt_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | case x 4 | in 1 | 2 5 | :ok 6 | in 3 | 4 | 5 7 | :ok 8 | end 9 | end 10 | 11 | ## assert 12 | class Object 13 | def check: (untyped) -> :ok 14 | end 15 | -------------------------------------------------------------------------------- /scenario/patterns/array_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class MyArray 3 | end 4 | 5 | def check(x) 6 | case x 7 | in 1, 2, 3 8 | :foo 9 | in [1, 2, 3, *] 10 | :bar 11 | in [String] 12 | :baz # TODO: this should be excluded 13 | in MyArray[1, 2, 3] 14 | :qux 15 | in [1,] 16 | :waldo 17 | else 18 | :zzz 19 | end 20 | end 21 | 22 | check([1].to_a) 23 | 24 | ## assert 25 | class MyArray 26 | end 27 | class Object 28 | def check: (Array[Integer]) -> (:bar | :baz | :foo | :qux | :waldo | :zzz) 29 | end 30 | -------------------------------------------------------------------------------- /scenario/patterns/capture.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(a) 3 | case a 4 | in [Integer => n, String => s] 5 | [n, s] 6 | end 7 | end 8 | 9 | check([42, "foo"]) 10 | -------------------------------------------------------------------------------- /scenario/patterns/const_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | case x 4 | in Integer 5 | :int 6 | in String 7 | :str 8 | end 9 | end 10 | 11 | check(1) 12 | check("foo") 13 | 14 | ## assert 15 | class Object 16 | def check: (Integer | String) -> (:int | :str) 17 | end 18 | -------------------------------------------------------------------------------- /scenario/patterns/find_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | case x 4 | in *a, Integer, *b 5 | :foo 6 | in *a, String, *b 7 | :bar # TODO: this should be excluded 8 | else 9 | :zzz 10 | end 11 | end 12 | 13 | check([1].to_a) 14 | 15 | ## assert 16 | class Object 17 | def check: (Array[Integer]) -> (:bar | :foo | :zzz) 18 | end 19 | -------------------------------------------------------------------------------- /scenario/patterns/hash_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class MyHash 3 | end 4 | 5 | def check(x) 6 | case x 7 | in { a: Integer } 8 | :foo 9 | in { a: String, ** } 10 | :bar # TODO: this should be excluded 11 | in { a: } 12 | :baz 13 | in MyHash[a: Integer] 14 | :qux 15 | else 16 | :zzz 17 | end 18 | end 19 | 20 | check({ a: 42 }) 21 | 22 | ## assert 23 | class MyHash 24 | end 25 | class Object 26 | def check: (Hash[:a, Integer]) -> (:bar | :baz | :foo | :qux | :zzz) 27 | end 28 | -------------------------------------------------------------------------------- /scenario/patterns/if_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def cond?(x) 3 | x 4 | end 5 | 6 | def check(x) 7 | case x 8 | in 1 if cond?(:ok) 9 | :ok 10 | end 11 | end 12 | 13 | ## assert 14 | class Object 15 | def cond?: (:ok) -> :ok 16 | def check: (untyped) -> :ok 17 | end 18 | -------------------------------------------------------------------------------- /scenario/patterns/in_match.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | x in Integer 4 | end 5 | 6 | check(1) 7 | check("str") 8 | 9 | ## assert 10 | class Object 11 | def check: (Integer | String) -> bool 12 | end 13 | -------------------------------------------------------------------------------- /scenario/patterns/literal_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check_interpolation(x) 3 | end 4 | 5 | def check(x) 6 | case x 7 | in 1 8 | :int 9 | in 1.0 10 | :float 11 | in 1r 12 | :rational 13 | in 1i 14 | :complex 15 | in "foo" 16 | :string 17 | in "foo#{ check_interpolation(:ok_str) }" 18 | :interpolated_string 19 | in :foo 20 | :symbol 21 | in :"foo#{ check_interpolation(:ok_sym) }" 22 | :interpolated_symbol 23 | in nil 24 | :nil 25 | in false 26 | :false 27 | in true 28 | :false 29 | in __FILE__ 30 | :FILE 31 | in __LINE__ 32 | :LINE 33 | in __ENCODING__ 34 | :ENCODING 35 | in %w[foo bar] 36 | :w_lit 37 | else 38 | :zzz 39 | end 40 | end 41 | 42 | check(1) 43 | check(:AAA) 44 | 45 | ## assert 46 | class Object 47 | def check_interpolation: (:ok_str | :ok_sym) -> nil 48 | def check: (:AAA | Integer) -> (:ENCODING | :FILE | :LINE | :complex | :false | :float | :int | :interpolated_string | :interpolated_symbol | :nil | :rational | :string | :symbol | :w_lit | :zzz) 49 | end 50 | -------------------------------------------------------------------------------- /scenario/patterns/pin_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | v = 1 4 | case x 5 | in ^v 6 | 1 7 | in ^$v 8 | "str" 9 | in ^(1) 10 | 1.0 11 | end 12 | end 13 | 14 | check(1) 15 | check("foo") 16 | 17 | ## assert 18 | class Object 19 | def check: (Integer | String) -> (Float | Integer | String) 20 | end 21 | -------------------------------------------------------------------------------- /scenario/patterns/range_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | case x 4 | in (0..) 5 | :ok1 6 | in -1 7 | :ok2 8 | end 9 | end 10 | 11 | ## assert 12 | class Object 13 | def check: (untyped) -> (:ok1 | :ok2) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/patterns/right_assign.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | x => Integer 4 | x 5 | end 6 | 7 | check(1) 8 | check("str") 9 | 10 | ## assert 11 | class Object 12 | def check: (Integer | String) -> (Integer | String) 13 | end 14 | -------------------------------------------------------------------------------- /scenario/patterns/var_pat.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check(x) 3 | case x 4 | in y 5 | y # TODO! 6 | end 7 | end 8 | 9 | check(1) 10 | check("foo") 11 | 12 | ## assert 13 | class Object 14 | def check: (Integer | String) -> untyped 15 | end 16 | 17 | ## update: test.rb 18 | def check(x) 19 | case x 20 | in a, b, c, *rest 21 | [a, b, c, rest] # TODO! 22 | end 23 | end 24 | 25 | check(1) 26 | check("foo") 27 | 28 | ## assert 29 | class Object 30 | def check: (Integer | String) -> [untyped, untyped, untyped, untyped] 31 | end 32 | 33 | 34 | ## update: test.rb 35 | def check(x) 36 | case x 37 | in { a:, b:, c:, **rest } 38 | [a, b, c, rest] # TODO! 39 | end 40 | end 41 | 42 | check(1) 43 | check("foo") 44 | 45 | ## assert 46 | class Object 47 | def check: (Integer | String) -> [untyped, untyped, untyped, untyped] 48 | end 49 | -------------------------------------------------------------------------------- /scenario/rbs/any.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def test(x) 3 | return if x == :foo 4 | end 5 | 6 | test(:foo) 7 | test(:bar) 8 | 9 | ## diagnostics 10 | 11 | ## assert 12 | class Object 13 | def test: (:bar | :foo) -> nil 14 | end 15 | -------------------------------------------------------------------------------- /scenario/rbs/attr.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class A 3 | attr_reader foo: Integer 4 | attr_writer foo: Integer | Float 5 | 6 | attr_accessor bar: String 7 | end 8 | 9 | ## update: test.rb 10 | def test1 11 | a = A.new 12 | a.foo = 42.0 13 | a.foo 14 | end 15 | 16 | def test2 17 | a = A.new 18 | a.bar = "foo" 19 | a.bar 20 | end 21 | 22 | ## assert: test.rb 23 | class Object 24 | def test1: -> Integer 25 | def test2: -> String 26 | end 27 | 28 | ## hover: test.rb:3:4 29 | A#foo= : (::Integer | ::Float) -> ::Integer | ::Float 30 | 31 | ## hover: test.rb:4:4 32 | A#foo : -> ::Integer 33 | 34 | ## hover: test.rb:9:4 35 | A#bar= : (::String) -> ::String 36 | 37 | ## hover: test.rb:10:4 38 | A#bar : -> ::String 39 | -------------------------------------------------------------------------------- /scenario/rbs/basic1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (Integer) -> Integer | (String) -> String 4 | end 5 | 6 | ## update: test.rb 7 | class C 8 | def bar 9 | foo(1) 10 | end 11 | end 12 | 13 | ## assert: test.rb 14 | class C 15 | def bar: -> Integer 16 | end 17 | 18 | ## update: test.rbs 19 | class C 20 | def foo: (Integer) -> Float | (String) -> String 21 | end 22 | 23 | ## assert: test.rb 24 | class C 25 | def bar: -> Float 26 | end 27 | -------------------------------------------------------------------------------- /scenario/rbs/basic2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (Integer) -> Integer 4 | end 5 | 6 | ## update: test.rb 7 | class C 8 | def foo(n) 9 | bar(n) 10 | end 11 | 12 | def bar(n) 13 | end 14 | end 15 | 16 | ## assert: test.rb 17 | class C 18 | def foo: (Integer) -> nil 19 | def bar: (Integer) -> nil 20 | end 21 | -------------------------------------------------------------------------------- /scenario/rbs/block.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def no_block: -> :ok 4 | def optional_block: ?{ (Integer) -> Integer } -> :ok 5 | def required_block: { (Integer) -> Integer } -> :ok 6 | end 7 | 8 | ## update: test.rb 9 | def test1 10 | no_block 11 | end 12 | def test2 13 | no_block { } 14 | end 15 | def test3 16 | optional_block 17 | end 18 | def test4 19 | optional_block { } 20 | end 21 | def test5 22 | required_block 23 | end 24 | def test6 25 | required_block { } 26 | end 27 | 28 | ## assert 29 | class Object 30 | def test1: -> :ok 31 | def test2: -> :ok 32 | def test3: -> :ok 33 | def test4: -> :ok 34 | def test5: -> :ok 35 | def test6: -> :ok 36 | end 37 | 38 | ## diagnostics 39 | (5,2)-(5,10): block is not expected 40 | (11,2)-(11,20): expected: Integer; actual: nil 41 | (14,2)-(14,16): block is expected 42 | (17,2)-(17,20): expected: Integer; actual: nil 43 | -------------------------------------------------------------------------------- /scenario/rbs/change-scope.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rbs 2 | class Foo 3 | def self.foo: (singleton(A)) -> :foo_a | (singleton(::A)) -> :top_a 4 | end 5 | 6 | ## update: test1.rbs 7 | class A 8 | end 9 | class Foo 10 | class A 11 | end 12 | end 13 | 14 | ## update: test.rb 15 | def test1 16 | Foo.foo(Foo::A) 17 | end 18 | 19 | def test2 20 | Foo.foo(A) 21 | end 22 | 23 | ## assert: test.rb 24 | class Object 25 | def test1: -> :foo_a 26 | def test2: -> :top_a 27 | end 28 | -------------------------------------------------------------------------------- /scenario/rbs/change-scope2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rbs 2 | class D 3 | end 4 | class C 5 | CONST: D 6 | end 7 | 8 | ## update: test.rb 9 | def test 10 | C::CONST 11 | end 12 | 13 | ## assert: test.rb 14 | class Object 15 | def test: -> D 16 | end 17 | 18 | ## update: test1.rbs 19 | class C 20 | class D 21 | end 22 | end 23 | 24 | ## assert: test.rb 25 | class Object 26 | def test: -> C::D 27 | end 28 | -------------------------------------------------------------------------------- /scenario/rbs/change-superclass.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rbs 2 | class Foo 3 | def self.foo: (A) -> :foo_a 4 | end 5 | 6 | ## update: test.rb 7 | class A 8 | end 9 | class B 10 | end 11 | def test 12 | Foo.foo(B.new) 13 | end 14 | 15 | ## assert: test.rb 16 | class A 17 | end 18 | class B 19 | end 20 | class Object 21 | def test: -> :foo_a 22 | end 23 | 24 | ## diagnostics: test.rb 25 | (6,6)-(6,9): wrong type of arguments 26 | 27 | ## update: test.rb 28 | class A 29 | end 30 | class B < A 31 | end 32 | def test 33 | Foo.foo(B.new) 34 | end 35 | 36 | ## assert: test.rb 37 | class A 38 | end 39 | class B < A 40 | end 41 | class Object 42 | def test: -> :foo_a 43 | end 44 | 45 | ## diagnostics: test.rb 46 | -------------------------------------------------------------------------------- /scenario/rbs/change-superclass2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class A 3 | end 4 | class B < A 5 | end 6 | class C < B 7 | end 8 | class D < C 9 | end 10 | 11 | ## update: test1.rbs 12 | class Object 13 | def accept_a: (A) -> :a 14 | def accept_b: (B) -> :b 15 | def accept_c: (C) -> :c 16 | def accept_d: (D) -> :d 17 | end 18 | 19 | ## update: test.rb 20 | 21 | def test_a_a = accept_a(A.new) 22 | def test_a_b = accept_a(B.new) 23 | def test_a_c = accept_a(C.new) 24 | def test_a_d = accept_a(D.new) 25 | 26 | def test_b_a = accept_b(A.new) 27 | def test_b_b = accept_b(B.new) 28 | def test_b_c = accept_b(C.new) 29 | def test_b_d = accept_b(D.new) 30 | 31 | def test_c_a = accept_c(A.new) 32 | def test_c_b = accept_c(B.new) 33 | def test_c_c = accept_c(C.new) 34 | def test_c_d = accept_c(D.new) 35 | 36 | def test_d_a = accept_d(A.new) 37 | def test_d_b = accept_d(B.new) 38 | def test_d_c = accept_d(C.new) 39 | def test_d_d = accept_d(D.new) 40 | 41 | ## assert: test.rb 42 | class Object 43 | def test_a_a: -> :a 44 | def test_a_b: -> :a 45 | def test_a_c: -> :a 46 | def test_a_d: -> :a 47 | def test_b_a: -> :b 48 | def test_b_b: -> :b 49 | def test_b_c: -> :b 50 | def test_b_d: -> :b 51 | def test_c_a: -> :c 52 | def test_c_b: -> :c 53 | def test_c_c: -> :c 54 | def test_c_d: -> :c 55 | def test_d_a: -> :d 56 | def test_d_b: -> :d 57 | def test_d_c: -> :d 58 | def test_d_d: -> :d 59 | end 60 | 61 | ## diagnostics: test.rb 62 | (7,15)-(7,23): wrong type of arguments 63 | (12,15)-(12,23): wrong type of arguments 64 | (13,15)-(13,23): wrong type of arguments 65 | (17,15)-(17,23): wrong type of arguments 66 | (18,15)-(18,23): wrong type of arguments 67 | (19,15)-(19,23): wrong type of arguments 68 | 69 | ## update: test.rbs 70 | class A 71 | end 72 | class B < A 73 | end 74 | class C 75 | end 76 | class C2 < B 77 | end 78 | class D < C2 79 | end 80 | 81 | ## assert: test.rb 82 | class Object 83 | def test_a_a: -> :a 84 | def test_a_b: -> :a 85 | def test_a_c: -> :a 86 | def test_a_d: -> :a 87 | def test_b_a: -> :b 88 | def test_b_b: -> :b 89 | def test_b_c: -> :b 90 | def test_b_d: -> :b 91 | def test_c_a: -> :c 92 | def test_c_b: -> :c 93 | def test_c_c: -> :c 94 | def test_c_d: -> :c 95 | def test_d_a: -> :d 96 | def test_d_b: -> :d 97 | def test_d_c: -> :d 98 | def test_d_d: -> :d 99 | end 100 | 101 | ## diagnostics: test.rb 102 | (4,15)-(4,23): wrong type of arguments 103 | (7,15)-(7,23): wrong type of arguments 104 | (9,15)-(9,23): wrong type of arguments 105 | (12,15)-(12,23): wrong type of arguments 106 | (13,15)-(13,23): wrong type of arguments 107 | (15,15)-(15,23): wrong type of arguments 108 | (17,15)-(17,23): wrong type of arguments 109 | (18,15)-(18,23): wrong type of arguments 110 | (19,15)-(19,23): wrong type of arguments 111 | -------------------------------------------------------------------------------- /scenario/rbs/check-block-return.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | #: { () -> Integer } -> void 3 | def foo 4 | yield 5 | end 6 | 7 | foo do 8 | next 9 | 10 | next "str" 11 | 12 | 1.0 13 | end 14 | 15 | ## diagnostics: test0.rb 16 | (11,2)-(11,5): expected: Integer; actual: Float 17 | (7,2)-(7,6): expected: Integer; actual: nil 18 | (9,2)-(9,12): expected: Integer; actual: String 19 | -------------------------------------------------------------------------------- /scenario/rbs/check-return-type.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | #: -> Integer 3 | def foo 4 | return 5 | 6 | return "str" 7 | 8 | 1.0 9 | end 10 | 11 | ## diagnostics 12 | (7,2)-(7,5): expected: Integer; actual: Float 13 | (3,2)-(3,8): expected: Integer; actual: nil 14 | (5,2)-(5,14): expected: Integer; actual: String 15 | -------------------------------------------------------------------------------- /scenario/rbs/check-return-type2.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class Bar 3 | end 4 | 5 | class Foo 6 | #: -> Bar 7 | def foo 8 | ::Bar.new 9 | end 10 | end 11 | 12 | ## update: test1.rb 13 | class Foo 14 | class Bar 15 | end 16 | end 17 | 18 | ## diagnostics: test0.rb 19 | (7,4)-(7,13): expected: Foo::Bar; actual: Bar 20 | -------------------------------------------------------------------------------- /scenario/rbs/check-return-type3.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | end 4 | class D 5 | end 6 | 7 | ## update: test1.rb 8 | class Foo 9 | #: -> C 10 | def foo 11 | D.new 12 | end 13 | end 14 | 15 | ## diagnostics: test1.rb 16 | (4,4)-(4,9): expected: C; actual: D 17 | 18 | ## update: test0.rb 19 | class C 20 | end 21 | class D < C 22 | end 23 | 24 | ## diagnostics: test1.rb 25 | -------------------------------------------------------------------------------- /scenario/rbs/check-return-type4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M 3 | def foo: -> Integer 4 | end 5 | 6 | ## update: test.rb 7 | module M 8 | def foo 9 | "string" 10 | end 11 | end 12 | 13 | ## diagnostics 14 | (3,4)-(3,12): expected: Integer; actual: String 15 | -------------------------------------------------------------------------------- /scenario/rbs/check-return-type5.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: -> Foo 4 | end 5 | 6 | ## update: test.rb 7 | class Foo 8 | def initialize 9 | @foo = 1 10 | end 11 | 12 | attr_reader :foo 13 | end 14 | 15 | ## diagnostics: test.rb 16 | (6,2)-(6,18): expected: Foo; actual: Integer 17 | -------------------------------------------------------------------------------- /scenario/rbs/inline-hover.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | #: (Integer) -> void 3 | def check(var) # TODO: fix "??? no type ???" 4 | var 5 | end 6 | 7 | ## hover: test.rb:2:11 8 | ??? no type ??? 9 | 10 | ## hover: test.rb:3:3 11 | Integer 12 | -------------------------------------------------------------------------------- /scenario/rbs/inline.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | #: (Integer) -> Integer 4 | def foo(n) 5 | raise NotImplementedError.new # TODO: support "raise NotImplementedError" 6 | end 7 | 8 | def bar 9 | foo(1) 10 | end 11 | end 12 | 13 | ## assert 14 | class C 15 | def foo: (Integer) -> bot 16 | def bar: -> Integer 17 | end 18 | -------------------------------------------------------------------------------- /scenario/rbs/interface1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Foo 3 | def foo: (Integer) -> String 4 | end 5 | 6 | class Object 7 | def create_foo: -> _Foo 8 | end 9 | 10 | ## update: test.rb 11 | def test 12 | x = create_foo 13 | end 14 | 15 | ## assert 16 | class Object 17 | def test: -> _Foo 18 | end 19 | 20 | ## update: test.rb 21 | 22 | def test 23 | x = create_foo 24 | x.foo(42) 25 | end 26 | 27 | ## assert 28 | class Object 29 | def test: -> String 30 | end 31 | -------------------------------------------------------------------------------- /scenario/rbs/interface2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | interface _Foo 3 | def foo: (Integer) -> String 4 | end 5 | 6 | class MyFoo 7 | # Currently, TypeProf handles interfaces as a nominal type, so the following line is necessary. 8 | include _Foo 9 | 10 | def foo: (Integer) -> String 11 | end 12 | 13 | class Object 14 | def accept_foo: (_Foo) -> :ok 15 | end 16 | 17 | ## update: test.rb 18 | def main 19 | accept_foo(MyFoo.new) 20 | end 21 | 22 | ## assert: test.rb 23 | class Object 24 | def main: -> :ok 25 | end 26 | -------------------------------------------------------------------------------- /scenario/rbs/module1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M 3 | end 4 | 5 | class C 6 | include M 7 | end 8 | 9 | class Object 10 | def accept_m: (M) -> String 11 | end 12 | 13 | ## update: test.rb 14 | def test 15 | accept_m(C.new) 16 | end 17 | 18 | ## assert 19 | class Object 20 | def test: -> String 21 | end 22 | -------------------------------------------------------------------------------- /scenario/rbs/module2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M 3 | end 4 | 5 | class Object 6 | def accept_m: (M) -> String 7 | end 8 | 9 | ## update: test.rb 10 | class C 11 | include M 12 | end 13 | 14 | def test 15 | accept_m(C.new) 16 | end 17 | 18 | ## assert 19 | class C 20 | include M 21 | end 22 | class Object 23 | def test: -> String 24 | end 25 | -------------------------------------------------------------------------------- /scenario/rbs/module3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | module M[X] 3 | end 4 | 5 | class C[X] 6 | include M[X] 7 | end 8 | 9 | class D < C[Integer] 10 | end 11 | 12 | class Object 13 | def accept_m: (M[String]) -> :str 14 | | (M[Integer]) -> :int 15 | | (M[Numeric]) -> :num 16 | | (M[untyped]) -> :untyped 17 | end 18 | 19 | ## update: test.rb 20 | def test 21 | accept_m(D.new) 22 | end 23 | 24 | ## assert 25 | class Object 26 | def test: -> (:int | :num | :untyped) 27 | end 28 | -------------------------------------------------------------------------------- /scenario/rbs/no-overload.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: (Integer) -> Integer 4 | | (String) -> String 5 | end 6 | 7 | ## update: test.rb 8 | foo(1) 9 | foo("1") 10 | foo(1.0) 11 | 12 | ## diagnostics: test.rb 13 | (3,0)-(3,3): failed to resolve overloads 14 | -------------------------------------------------------------------------------- /scenario/rbs/no-type-var.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: (Hash) -> void 4 | def bar: -> Hash 5 | end 6 | 7 | ## update: test.rb 8 | Foo.new.foo({}) 9 | Foo.new.bar.map {} 10 | -------------------------------------------------------------------------------- /scenario/rbs/param1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | def foo: -> X 4 | def self.create_int_foo: -> Foo[Integer] 5 | end 6 | 7 | ## update: test.rb 8 | def test 9 | Foo.create_int_foo.foo 10 | end 11 | 12 | ## assert: test.rb 13 | class Object 14 | def test: -> Integer 15 | end 16 | -------------------------------------------------------------------------------- /scenario/rbs/param2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def foo: [U] (U) -> (U | :a) 4 | def bar: [U] (U, U) -> U 5 | end 6 | 7 | ## update: test.rb 8 | def test1 9 | foo("str") 10 | end 11 | 12 | def test2 13 | bar(1, "str") 14 | end 15 | 16 | ## assert: test.rb 17 | class Object 18 | def test1: -> (:a | String) 19 | def test2: -> (Integer | String) 20 | end 21 | -------------------------------------------------------------------------------- /scenario/rbs/param3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def baz: [U] (Array[U]) -> U 4 | end 5 | 6 | ## update: test.rb 7 | def test3 8 | baz([1, 2, 3]) 9 | end 10 | 11 | ## assert: test.rb 12 | class Object 13 | def test3: -> Integer 14 | end 15 | -------------------------------------------------------------------------------- /scenario/rbs/param4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[Y] 3 | end 4 | class Bar[X] < Foo[[X, X]] 5 | def self.create: -> Bar[Integer] 6 | end 7 | class Object 8 | def foo: [Z] (Foo[Z]) -> Z 9 | end 10 | 11 | ## update: test.rb 12 | def test 13 | foo(Bar.create) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/rbs/param5.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | include Enumerable[[X, X]] 4 | end 5 | 6 | class Bar < Foo[Integer] 7 | end 8 | 9 | ## update: test.rb 10 | def test 11 | Bar.new.map {|x| x } 12 | end 13 | 14 | ## assert: test.rb 15 | class Object 16 | def test: -> Array[[Integer, Integer]] 17 | end 18 | -------------------------------------------------------------------------------- /scenario/rbs/param6.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | include Enumerable[Integer] 4 | end 5 | 6 | ## update: test.rb 7 | def foo 8 | Foo.new.map {|x| return x; :a } 9 | end 10 | 11 | ## assert: test.rb 12 | class Object 13 | def foo: -> (Array[:a] | Integer) 14 | end 15 | -------------------------------------------------------------------------------- /scenario/rbs/param7.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C[X] 3 | end 4 | 5 | class Object 6 | def get_c_int: -> C[Integer] 7 | def accept_c: (C[String]) -> :str 8 | | (C[Integer]) -> :int 9 | | (C[Numeric]) -> :num 10 | | (C[untyped]) -> :untyped 11 | end 12 | 13 | ## update: test.rb 14 | def test 15 | accept_c(get_c_int) 16 | end 17 | 18 | ## assert 19 | class Object 20 | def test: -> (:int | :num | :untyped) 21 | end 22 | -------------------------------------------------------------------------------- /scenario/rbs/recursive1.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def initialize 4 | @elem = [] 5 | end 6 | 7 | def foo 8 | @elem = @elem + [1] 9 | end 10 | end 11 | 12 | ## assert 13 | class Foo 14 | def initialize: -> [] 15 | def foo: -> Array[Integer] 16 | end 17 | -------------------------------------------------------------------------------- /scenario/rbs/recursive2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | def self.gen: -> Foo[Integer] 4 | def dup_like: -> Foo[X] 5 | end 6 | 7 | ## update: test.rb 8 | class Bar 9 | def test 10 | @elem = Foo.gen 11 | @elem = @elem.dup_like 12 | end 13 | end 14 | 15 | ## assert 16 | class Bar 17 | def test: -> Foo[Integer] 18 | end 19 | -------------------------------------------------------------------------------- /scenario/rbs/remove-class.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (singleton(C)) -> :ok 4 | end 5 | 6 | ## update: test.rb 7 | C = 1 8 | class Foo 9 | def foo 10 | C 11 | end 12 | end 13 | 14 | ## assert: test.rb 15 | C: Integer 16 | class Foo 17 | def foo: -> (Integer | singleton(C)) 18 | end 19 | 20 | ## update: test.rbs 21 | # class C is removed 22 | 23 | ## assert: test.rb 24 | C: Integer 25 | class Foo 26 | def foo: -> Integer 27 | end 28 | -------------------------------------------------------------------------------- /scenario/rbs/self-types.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def self.f1: -> self 4 | def self.f2: -> instance 5 | def self.f3: -> class 6 | def f4: -> self 7 | def f5: -> instance 8 | def f6: -> class 9 | end 10 | 11 | class D < C 12 | end 13 | 14 | ## update: test.rb 15 | def test1 = D.f1 16 | def test2 = D.f2 17 | def test3 = D.f3 18 | def test4 = D.new.f4 19 | def test5 = D.new.f5 20 | def test6 = D.new.f6 21 | 22 | ## assert 23 | class Object 24 | def test1: -> singleton(D) 25 | def test2: -> D 26 | def test3: -> singleton(D) 27 | def test4: -> D 28 | def test5: -> D 29 | def test6: -> singleton(D) 30 | end 31 | -------------------------------------------------------------------------------- /scenario/rbs/superclass1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: -> Integer 4 | end 5 | 6 | class Bar < Foo 7 | end 8 | 9 | ## update: test.rb 10 | def test 11 | Bar.new.foo 12 | end 13 | 14 | ## assert: test.rb 15 | class Object 16 | def test: -> Integer 17 | end 18 | -------------------------------------------------------------------------------- /scenario/rbs/superclass2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | def foo: -> X 4 | end 5 | 6 | class Bar < Foo[[Integer, String]] 7 | end 8 | 9 | ## update: test.rb 10 | def test 11 | Bar.new.foo 12 | end 13 | 14 | ## assert: test.rb 15 | class Object 16 | def test: -> [Integer, String] 17 | end 18 | -------------------------------------------------------------------------------- /scenario/rbs/symbol.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (:a) -> :ok 4 | def bar: (Symbol) -> :ok 5 | end 6 | 7 | ## update: test.rb 8 | def test1 9 | C.new.foo(:a) 10 | end 11 | 12 | def test2 13 | C.new.foo(:b) 14 | end 15 | 16 | def test3 17 | C.new.bar(:a) 18 | end 19 | 20 | def test4 21 | C.new.bar(:b) 22 | end 23 | 24 | ## assert 25 | class Object 26 | def test1: -> :ok 27 | def test2: -> :ok 28 | def test3: -> :ok 29 | def test4: -> :ok 30 | end 31 | 32 | ## diagnostics 33 | (6,8)-(6,11): wrong type of arguments 34 | -------------------------------------------------------------------------------- /scenario/rbs/type-alias.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | type a = Integer 3 | class Foo 4 | type a = Integer | String 5 | def foo: (a) -> a 6 | end 7 | 8 | ## update: test.rb 9 | def test1 10 | Foo.new.foo(1) 11 | end 12 | 13 | def test2 14 | Foo.new.foo("str") 15 | end 16 | 17 | def test3(unknown) 18 | Foo.new.foo(unknown) 19 | end 20 | 21 | ## assert: test.rb 22 | class Object 23 | def test1: -> (Integer | String) 24 | def test2: -> (Integer | String) 25 | def test3: (untyped) -> (Integer | String) 26 | end 27 | 28 | ## diagnostics: test.rb 29 | (10,10)-(10,13): wrong type of arguments 30 | 31 | ## update: test.rbs 32 | type a = Integer 33 | class Foo 34 | type a = Integer | String 35 | def foo: (::a) -> ::a 36 | end 37 | 38 | ## assert: test.rb 39 | class Object 40 | def test1: -> Integer 41 | def test2: -> Integer 42 | def test3: (untyped) -> Integer 43 | end 44 | 45 | ## diagnostics: test.rb 46 | (6,10)-(6,13): wrong type of arguments 47 | (10,10)-(10,13): wrong type of arguments 48 | 49 | ## update: test.rbs 50 | type a = Integer 51 | class Foo 52 | def foo: (a) -> a 53 | end 54 | 55 | ## assert: test.rb 56 | class Object 57 | def test1: -> Integer 58 | def test2: -> Integer 59 | def test3: (untyped) -> Integer 60 | end 61 | 62 | ## diagnostics: test.rb 63 | (6,10)-(6,13): wrong type of arguments 64 | (10,10)-(10,13): wrong type of arguments 65 | 66 | ## update: test.rbs 67 | class Bar 68 | type a = Integer 69 | end 70 | class Foo 71 | def foo: (Bar::a) -> Bar::a 72 | end 73 | 74 | ## assert: test.rb 75 | class Object 76 | def test1: -> Integer 77 | def test2: -> Integer 78 | def test3: (untyped) -> Integer 79 | end 80 | 81 | ## diagnostics: test.rb 82 | (6,10)-(6,13): wrong type of arguments 83 | (10,10)-(10,13): wrong type of arguments 84 | -------------------------------------------------------------------------------- /scenario/rbs/type-alias2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | type a[T] = Array[T] 4 | def foo: (a[String]) -> a[Integer] 5 | end 6 | 7 | ## update: test.rb 8 | def foo 9 | Foo.new.foo(["str"]) 10 | end 11 | 12 | ## assert 13 | class Object 14 | def foo: -> Array[Integer] 15 | end 16 | -------------------------------------------------------------------------------- /scenario/rbs/type-var1.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | def foo: (X) -> void 4 | end 5 | 6 | ## update: test.rb 7 | class Foo 8 | def foo(x) # temporarily "var[X]" is printed 9 | end 10 | end 11 | 12 | ## assert: test.rb 13 | class Foo 14 | def foo: (var[X]) -> nil 15 | end 16 | 17 | ## update: test.rb 18 | class Foo 19 | def foo(x) 20 | x.bar # currently, X is handled like Object 21 | nil 22 | end 23 | end 24 | 25 | ## assert: test.rb 26 | class Foo 27 | def foo: (var[X]) -> nil 28 | end 29 | 30 | ## diagnostics 31 | (3,6)-(3,9): undefined method: var[X]#bar 32 | 33 | ## update: test.rbs 34 | class Foo[X] 35 | def foo: (X) -> X 36 | end 37 | 38 | ## update: test.rb 39 | class Foo 40 | def foo(x) 41 | x 42 | end 43 | end 44 | 45 | ## assert: test.rb 46 | class Foo 47 | def foo: (var[X]) -> var[X] 48 | end 49 | -------------------------------------------------------------------------------- /scenario/rbs/type-var2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: [X] (X) -> void 4 | end 5 | 6 | ## update: test.rb 7 | class Foo 8 | def foo(x) # temporarily "var[X]" is printed 9 | end 10 | end 11 | 12 | ## assert: test.rb 13 | class Foo 14 | def foo: (var[X]) -> nil 15 | end 16 | 17 | ## update: test.rb 18 | class Foo 19 | def foo(x) 20 | x.bar # currently, X is handled like Object 21 | nil 22 | end 23 | end 24 | 25 | ## assert: test.rb 26 | class Foo 27 | def foo: (var[X]) -> nil 28 | end 29 | 30 | ## diagnostics 31 | (3,6)-(3,9): undefined method: var[X]#bar 32 | 33 | ## update: test.rbs 34 | class Foo 35 | def foo: [X] (X) -> X 36 | end 37 | 38 | ## update: test.rb 39 | class Foo 40 | def foo(x) 41 | x 42 | end 43 | end 44 | 45 | ## assert: test.rb 46 | class Foo 47 | def foo: (var[X]) -> var[X] 48 | end 49 | -------------------------------------------------------------------------------- /scenario/rbs/untyped-for-overload.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (:a) -> :A 4 | | (:b) -> :B 5 | end 6 | 7 | ## update: test.rb 8 | def check 9 | C.new.foo($untyped) 10 | end 11 | 12 | ## assert 13 | class Object 14 | def check: -> untyped 15 | end 16 | -------------------------------------------------------------------------------- /scenario/regressions/array-as-self.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Array 3 | def quote 4 | each {|s| s.quote } 5 | end 6 | end 7 | 8 | ## assert 9 | class Array 10 | def quote: -> Array[untyped] 11 | end 12 | -------------------------------------------------------------------------------- /scenario/regressions/array-zip.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def foo(cond, bar) 4 | foo = cond ? [] : [] 5 | foo.zip(bar) do |expr, vtx| 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /scenario/regressions/avoid-infinite-loop-2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def foo: -> Foo? 4 | def self.bar: (Foo) -> Foo 5 | end 6 | 7 | ## update: test.rb 8 | def check 9 | # The old infinite-loop scenario 10 | # 1. both @a and @b are untyped 11 | # 2. @b is now Foo because `@b = Foo.bar(@a)` and `Foo.bar: (Foo) -> Foo` and @a is untyped 12 | # 3. @a is now Foo? because of `@a = @b.foo` and @b is Foo 13 | # 4. @b is now untyped because `@b = Foo.bar(@a)` and `Foo.bar: (Foo) -> Foo` and @a is Foo | nil 14 | # 5. go to 2 15 | # 16 | # How did I fixed: 17 | # `Foo.bar: (Foo) -> Foo` should match against `Foo | nil` 18 | # (TODO: add a diagnostics for this) 19 | @a = @b.foo 20 | @b = Foo.bar(@a) 21 | end 22 | 23 | def check2 24 | @a = @b[0] 25 | @b = '/' + @a 26 | end 27 | -------------------------------------------------------------------------------- /scenario/regressions/avoid-infinite-loop-3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | module A 3 | module A 4 | end 5 | end 6 | 7 | module B 8 | include A 9 | end 10 | -------------------------------------------------------------------------------- /scenario/regressions/avoid-infinite-loop-4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class C 3 | def foo: (C) -> C 4 | def bar: -> String 5 | end 6 | 7 | ## update: test.rb 8 | def check 9 | c = C.new 10 | @a = @b.bar 11 | @b = c.foo(@a) 12 | end 13 | -------------------------------------------------------------------------------- /scenario/regressions/avoid-infinite-loop.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def check: () -> Array[bool] 4 | end 5 | 6 | ## update: test.rb 7 | def foo(node) 8 | node = Foo.new 9 | while true 10 | node, = node.check 11 | end 12 | end 13 | 14 | foo 15 | 16 | ## assert 17 | class Object 18 | def foo: (untyped) -> nil 19 | end 20 | -------------------------------------------------------------------------------- /scenario/regressions/double-edge-record-block.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&blk) 3 | obj = [1] 4 | obj.each(&blk) 5 | obj.each(&blk) 6 | end 7 | 8 | foo {|x, y|} 9 | -------------------------------------------------------------------------------- /scenario/regressions/iasgn-multi-edge.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo(n) 4 | # assigning the same lvar to an ivar multiple times 5 | # may make multi-edge from the lvar to the ivar 6 | @x = n 7 | @x = n 8 | end 9 | end 10 | 11 | ## assert 12 | class Foo 13 | def foo: (untyped) -> untyped 14 | end 15 | -------------------------------------------------------------------------------- /scenario/regressions/include-enumerable.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | include Enumerable 4 | 5 | def foo 6 | ary = [] 7 | ary.each do |ary| 8 | add ary 9 | end 10 | end 11 | end 12 | 13 | ## assert 14 | class Foo 15 | include Enumerable 16 | def foo: -> Array[untyped] 17 | end 18 | 19 | ## diagnostics 20 | (7,6)-(7,9): undefined method: Foo#add 21 | -------------------------------------------------------------------------------- /scenario/regressions/ivar-stuck-case.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo 3 | def check: [T] (T) -> [T] 4 | end 5 | 6 | ## update: test.rb 7 | class Foo 8 | def foo 9 | @foo = [] 10 | @foo = check(@foo) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /scenario/regressions/multi-next.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | ["str"].map do |x| 4 | next x 5 | next x 6 | 1 7 | end 8 | end 9 | 10 | ## assert 11 | class Object 12 | def check: -> Array[Integer | String] 13 | end 14 | -------------------------------------------------------------------------------- /scenario/regressions/multi_edge_to_gvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def check 3 | while true 4 | opt = 1 5 | if cond 6 | $foo = opt 7 | else 8 | $foo = opt 9 | end 10 | end 11 | end 12 | 13 | ## assert 14 | class Object 15 | def check: -> nil 16 | end 17 | -------------------------------------------------------------------------------- /scenario/regressions/self-type-var.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check2 3 | @ary = [].to_a 4 | @ary = @ary.concat(@ary) 5 | @ary = @ary.concat(@ary) 6 | end 7 | -------------------------------------------------------------------------------- /scenario/regressions/splat-block.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Foo[X] 3 | def self.get1: -> Foo[:a] 4 | def self.get2: -> Foo[:b] 5 | def foo: [U] (U) { ([ U, Integer ]) -> void } -> void 6 | end 7 | 8 | ## update: test.rb 9 | def check(cond) 10 | a = cond ? Foo.get1 : Foo.get2 11 | a.foo(1) do |x, y| 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /scenario/service/code_lens.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo(n) 4 | 1 5 | end 6 | 7 | def bar(n) 8 | "str" 9 | end 10 | 11 | #: (Integer) -> Integer 12 | def baz(n) 13 | 1 14 | end 15 | end 16 | 17 | def test(x) 18 | x 19 | end 20 | 21 | Foo.new.foo(1.0) 22 | test(Foo.new) 23 | 24 | ## code_lens 25 | (2,2): (Float) -> Integer 26 | (6,2): (untyped) -> String 27 | (16,0): (Foo) -> Foo 28 | -------------------------------------------------------------------------------- /scenario/service/code_lens_update.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo(n) 4 | 1 5 | end 6 | end 7 | 8 | ## code_lens 9 | (2,2): (untyped) -> Integer 10 | 11 | ## update 12 | class Foo 13 | # a line added and indentation changed 14 | def foo(n) 15 | 1 16 | end 17 | end 18 | 19 | ## code_lens 20 | (3,4): (untyped) -> Integer 21 | -------------------------------------------------------------------------------- /scenario/service/completion_dot.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | def foo(n) 4 | 1 5 | end 6 | def bar(n) 7 | "str" 8 | end 9 | #: (Foo) -> Foo 10 | def baz(_) 11 | _ 12 | end 13 | end 14 | 15 | def test1(x) 16 | x 17 | end 18 | 19 | def test2 20 | test1(Foo.new) 21 | end 22 | 23 | Foo.new.foo(1.0) 24 | test(Foo.new) 25 | 26 | ## completion: test.rb:15:2 27 | Foo#foo : (Float) -> Integer 28 | Foo#bar : (untyped) -> String 29 | Foo#baz : (Foo) -> Foo 30 | 31 | ## completion: test.rb:19:15 32 | Foo#foo : (Float) -> Integer 33 | Foo#bar : (untyped) -> String 34 | Foo#baz : (Foo) -> Foo 35 | -------------------------------------------------------------------------------- /scenario/service/completion_dot_module.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | module M 3 | def bar = :BAR 4 | end 5 | class P 6 | def baz = :BAZ 7 | end 8 | class C < P 9 | include M 10 | def foo = :FOO 11 | end 12 | x = C.new 13 | x 14 | 15 | ## completion: test.rb:12:0 16 | C#foo : -> :FOO 17 | M#bar : -> :BAR 18 | P#baz : -> :BAZ 19 | -------------------------------------------------------------------------------- /scenario/service/definition.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | BAR = 1 4 | 5 | attr_reader :bar_sym_reader, :baz_sym_reader 6 | attr_accessor :bar_sym_accessor, :baz_sym_accessor 7 | 8 | def initialize(n) 9 | @bar = n 10 | end 11 | 12 | def foo(n) 13 | end 14 | end 15 | 16 | Foo.new(1).foo(1.0) 17 | Foo.new(1).bar_sym_reader 18 | Foo.new(1).baz_sym_reader 19 | Foo.new(1).bar_sym_accessor 20 | Foo.new(1).baz_sym_accessor 21 | Foo::BAR 22 | Foo::BBAR = 1 23 | Foo::BBAR 24 | Foo::CCAR, Foo::DDAR = [1, 2] 25 | Foo::CCAR 26 | Foo::DDAR 27 | 28 | ## definition: test.rb:15:1 29 | test.rb:(1,6)-(1,9) # Jump to Foo class 30 | 31 | ## definition: test.rb:15:5 32 | test.rb:(7,6)-(7,16) # Jump Foo.initialize from Foo.new 33 | 34 | ## definition: test.rb:15:12 35 | test.rb:(11,6)-(11,9) # Jump to Foo#foo 36 | 37 | ## definition: test.rb:16:12 38 | test.rb:(4,14)-(4,29) # Jump to Foo#bar_sym_reader (first sym arg of attr_reader) 39 | 40 | ## definition: test.rb:17:12 41 | test.rb:(4,31)-(4,46) # Jump to Foo#baz_sym_reader (second sym arg of attr_reader) 42 | 43 | ## definition: test.rb:18:12 44 | test.rb:(5,16)-(5,33) # Jump to Foo#bar_sym_accessor (first sym arg of attr_accessor) 45 | 46 | ## definition: test.rb:19:12 47 | test.rb:(5,35)-(5,52) # Jump to Foo#baz_sym_accessor (second sym arg of attr_accessor) 48 | 49 | ## definition: test.rb:20:5 50 | test.rb:(2,2)-(2,5) # Jump to Foo#BAR (constant_write_node) 51 | 52 | ## definition: test.rb:22:5 53 | test.rb:(21,0)-(21,9) # Jump to Foo#BBAR (constant_path_write_node) 54 | 55 | ## definition: test.rb:24:5 56 | test.rb:(23,0)-(23,9) # Jump to Foo#CCAR (first arg of constant_path_target_node) 57 | 58 | ## definition: test.rb:25:5 59 | test.rb:(23,11)-(23,20) # Jump to Foo#DDAR (second arg of constant_path_target_node) 60 | -------------------------------------------------------------------------------- /scenario/service/hover.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(variable) 3 | variable + 1 4 | end 5 | 6 | def main(_) 7 | foo(2) 8 | end 9 | 10 | ## hover: test.rb:1:10 11 | Integer 12 | 13 | ## hover: test.rb:2:3 14 | Integer 15 | 16 | ## update 17 | def foo(nnn) 18 | nnn.times do |var| 19 | var 20 | end 21 | end 22 | 23 | foo(42) 24 | 25 | ## hover: test.rb:3:4 26 | Integer 27 | -------------------------------------------------------------------------------- /scenario/service/hover2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | #: () -> Integer 3 | def foo 4 | "string" 5 | end 6 | 7 | foo 8 | 9 | ## hover: test.rb:6:0 10 | Object#foo : -> ::Integer 11 | 12 | ## diagnostics 13 | (3,2)-(3,10): expected: Integer; actual: String 14 | 15 | ## update: test.rb 16 | #: () -> Integer? 17 | def foo 18 | "string" 19 | end 20 | 21 | foo 22 | 23 | ## hover: test.rb:6:0 24 | Object#foo : -> ::Integer? 25 | 26 | ## update: test.rb 27 | #: () -> (Integer | String)? 28 | def foo 29 | "string" 30 | end 31 | 32 | foo 33 | 34 | # TODO: The above test is mainly for SIG_TYPE#show 35 | 36 | ## hover: test.rb:6:0 37 | Object#foo : -> (::Integer | ::String)? 38 | -------------------------------------------------------------------------------- /scenario/service/hover3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | x = { 1 => 2 } 3 | x.map do |k, v| 4 | end 5 | 6 | # TODO: support showing type parameters 7 | 8 | ## hover: test.rb:2:3 9 | Hash[Integer, Integer]#map : -> ::Array[...] | -> ::Enumerator[...] 10 | -------------------------------------------------------------------------------- /scenario/service/hover4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rbs 2 | class Object 3 | def required_positional_args: (Integer) -> Integer 4 | 5 | def optional_positional_args: (?Integer) -> Integer 6 | 7 | def post_required_positional_args: (?Integer, Integer) -> Integer 8 | 9 | def rest_positional_args: (*Integer) -> Integer 10 | 11 | def rest_post_positional_args: (*Integer, Integer) -> Integer 12 | 13 | def required_keywords: (a: Integer) -> Integer 14 | 15 | def optional_keywords: (?a: Integer) -> Integer 16 | 17 | def rest_keywords: (**untyped) -> Integer 18 | end 19 | 20 | ## update: test.rb 21 | required_positional_args 22 | optional_positional_args 23 | post_required_positional_args 24 | rest_positional_args 25 | rest_post_positional_args 26 | required_keywords 27 | optional_keywords 28 | rest_keywords 29 | 30 | ## hover: test.rb:1:1 31 | Object#required_positional_args : (::Integer) -> ::Integer 32 | 33 | ## hover: test.rb:2:1 34 | Object#optional_positional_args : (?::Integer) -> ::Integer 35 | 36 | ## hover: test.rb:3:1 37 | Object#post_required_positional_args : (?::Integer, ::Integer) -> ::Integer 38 | 39 | ## hover: test.rb:4:1 40 | Object#rest_positional_args : (*::Integer) -> ::Integer 41 | 42 | ## hover: test.rb:5:1 43 | 44 | Object#rest_post_positional_args : (*::Integer, ::Integer) -> ::Integer 45 | 46 | ## hover: test.rb:6:1 47 | Object#required_keywords : (a: ::Integer) -> ::Integer 48 | 49 | ## hover: test.rb:7:1 50 | Object#optional_keywords : (?a: ::Integer) -> ::Integer 51 | 52 | ## hover: test.rb:8:1 53 | Object#rest_keywords : (**untyped) -> ::Integer 54 | -------------------------------------------------------------------------------- /scenario/service/references.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def initialize(n) 4 | end 5 | 6 | def foo(n) 7 | end 8 | end 9 | 10 | Foo.new(1).foo(1.0) 11 | Foo.new(1).foo(1.0) 12 | Foo.new(1).foo(1.0) 13 | 14 | ## references: test.rb:2:7 15 | test.rb:(9,0)-(9,10) 16 | test.rb:(10,0)-(10,10) 17 | test.rb:(11,0)-(11,10) 18 | 19 | ## references: test.rb:5:7 20 | test.rb:(9,0)-(9,19) 21 | test.rb:(10,0)-(10,19) 22 | test.rb:(11,0)-(11,19) 23 | -------------------------------------------------------------------------------- /scenario/service/references2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | module M 3 | class Foo 4 | def initialize(x) 5 | end 6 | end 7 | Foo::C = 1 8 | 9 | Foo.new(Foo::C) 10 | Foo.new(Foo::C) 11 | Foo.new(Foo::C) 12 | end 13 | 14 | ## references: test.rb:2:9 15 | test.rb:(2,8)-(2,11) 16 | test.rb:(6,2)-(6,5) 17 | test.rb:(8,2)-(8,5) 18 | test.rb:(8,10)-(8,13) 19 | test.rb:(9,2)-(9,5) 20 | test.rb:(9,10)-(9,13) 21 | test.rb:(10,2)-(10,5) 22 | test.rb:(10,10)-(10,13) 23 | 24 | ## update: test.rb 25 | Bar = 1 26 | Bar 27 | 28 | ## references: test.rb:1:1 29 | test.rb:(2,0)-(2,3) 30 | -------------------------------------------------------------------------------- /scenario/service/rename.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | def initialize(n) 4 | end 5 | 6 | def foo(n) 7 | end 8 | end 9 | 10 | Foo.new(1).foo(1.0) 11 | Foo.new(1).foo(1.0) 12 | Foo.new(1).foo(1.0) 13 | 14 | ## rename: test.rb:5:7 15 | test.rb:(5,6)-(5,9) 16 | test.rb:(9,11)-(9,14) 17 | test.rb:(10,11)-(10,14) 18 | test.rb:(11,11)-(11,14) 19 | -------------------------------------------------------------------------------- /scenario/service/rename2.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | class Foo 3 | end 4 | 5 | Foo = 1 6 | 7 | Foo 8 | Foo + Foo 9 | 10 | ## rename: test.rb:1:7 11 | test.rb:(1,6)-(1,9) 12 | test.rb:(6,0)-(6,3) 13 | test.rb:(7,0)-(7,3) 14 | test.rb:(7,6)-(7,9) 15 | test.rb:(4,0)-(4,3) 16 | -------------------------------------------------------------------------------- /scenario/service/rename3.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class Foo 3 | class Bar 4 | Baz = 1 5 | end 6 | end 7 | 8 | p Foo::Bar::Baz 9 | 10 | ## rename: test.rb:7:3 11 | test.rb:(1,6)-(1,9) 12 | test.rb:(7,2)-(7,5) 13 | 14 | ## rename: test.rb:7:8 15 | test.rb:(2,8)-(2,11) 16 | test.rb:(7,7)-(7,10) 17 | 18 | ## rename: test.rb:7:12 19 | test.rb:(3,4)-(3,7) 20 | test.rb:(7,12)-(7,15) 21 | -------------------------------------------------------------------------------- /scenario/service/rename4.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | Foo = 1 3 | Foo 4 | 5 | ## rename: test.rb:2:1 6 | test.rb:(1,0)-(1,3) 7 | test.rb:(2,0)-(2,3) 8 | 9 | ## rename: test.rb:1:1 10 | test.rb:(1,0)-(1,3) 11 | test.rb:(2,0)-(2,3) 12 | 13 | ## hover: test.rb:1:1 14 | Integer 15 | -------------------------------------------------------------------------------- /scenario/variable/and_write.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | $gv = :GVar0 3 | $gv &&= :GVar 4 | 5 | class C 6 | D &&= :ConstD 7 | @@cv &&= :CV0 8 | def get_lv 9 | lv = :LVar0 10 | lv &&= :LVar 11 | lv 12 | end 13 | def set_iv 14 | @iv = :IVar0 15 | @iv &&= :IVar 16 | end 17 | def get_iv = @iv 18 | def get_gv = $gv 19 | def set_cv 20 | @@cv = :CV 21 | end 22 | def get_cv = @@cv 23 | def get_index_asgn 24 | ary = [:IndexAsgn0] 25 | ary[0] &&= :IndexAsgn 26 | ary 27 | end 28 | def get_attr_asgn 29 | self.test_attr &&= :AttrAsgn 30 | end 31 | def test_attr = :AttrAsgn0 32 | def test_attr=(x) 33 | x 34 | end 35 | end 36 | C::E &&= :ConstE 37 | 38 | ## diagnostics 39 | ## assert 40 | class C 41 | C::D: :ConstD 42 | def get_lv: -> (:LVar | :LVar0) 43 | def set_iv: -> (:IVar | :IVar0) 44 | def get_iv: -> (:IVar | :IVar0) 45 | def get_gv: -> (:GVar | :GVar0) 46 | def set_cv: -> :CV 47 | def get_cv: -> (:CV | :CV0) 48 | def get_index_asgn: -> [:IndexAsgn | :IndexAsgn0] 49 | def get_attr_asgn: -> (:AttrAsgn | :AttrAsgn0) 50 | def test_attr: -> :AttrAsgn0 51 | def test_attr=: (:AttrAsgn | :AttrAsgn0) -> (:AttrAsgn | :AttrAsgn0) 52 | end 53 | C::E: :ConstE 54 | -------------------------------------------------------------------------------- /scenario/variable/cvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class A 3 | def foo 4 | @@x = :ok 5 | @@x 6 | end 7 | end 8 | 9 | ## assert 10 | class A 11 | def foo: -> :ok 12 | end 13 | 14 | ## update 15 | class B 16 | @@x = :ok 17 | 18 | def foo 19 | @@x 20 | end 21 | end 22 | 23 | ## assert 24 | class B 25 | def foo: -> :ok 26 | end 27 | -------------------------------------------------------------------------------- /scenario/variable/dvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(&blk) 3 | blk.call(42) 4 | end 5 | 6 | def bar 7 | a = "str" 8 | foo do |x| 9 | a = x 10 | a 11 | end 12 | a 13 | end 14 | 15 | ## assert 16 | class Object 17 | def foo: { (Integer) -> Integer } -> Integer 18 | def bar: -> (Integer | String) 19 | end 20 | -------------------------------------------------------------------------------- /scenario/variable/dvar2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo(x) 3 | x = "str" 4 | 1.times do |_| 5 | x = 42 6 | end 7 | x 8 | end 9 | 10 | def bar(x) 11 | x = "str" 12 | 1.times do |x| 13 | x = 42 14 | end 15 | x 16 | end 17 | 18 | ## assert 19 | class Object 20 | def foo: (untyped) -> (Integer | String) 21 | def bar: (untyped) -> String 22 | end 23 | -------------------------------------------------------------------------------- /scenario/variable/gvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | $foo = "str" 4 | end 5 | 6 | def bar 7 | $foo 8 | end 9 | 10 | def baz 11 | $VERBOSE 12 | end 13 | 14 | ## assert 15 | class Object 16 | def foo: -> String 17 | def bar: -> String 18 | def baz: -> bool? 19 | end 20 | -------------------------------------------------------------------------------- /scenario/variable/ivar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def initialize(x) 4 | @x = 42 5 | end 6 | 7 | def foo(_) 8 | @x 9 | end 10 | end 11 | 12 | class D < C 13 | def bar(_) 14 | @x 15 | @x 16 | @x 17 | end 18 | end 19 | 20 | ## assert 21 | class C 22 | def initialize: (untyped) -> Integer 23 | def foo: (untyped) -> Integer 24 | end 25 | class D < C 26 | def bar: (untyped) -> Integer 27 | end 28 | 29 | ## update 30 | class C 31 | def initialize(x) 32 | @x = "42" 33 | end 34 | 35 | def foo(_) 36 | @x 37 | end 38 | end 39 | 40 | class D < C 41 | def bar(_) 42 | @x 43 | end 44 | end 45 | 46 | ## assert 47 | class C 48 | def initialize: (untyped) -> String 49 | def foo: (untyped) -> String 50 | end 51 | class D < C 52 | def bar: (untyped) -> String 53 | end 54 | -------------------------------------------------------------------------------- /scenario/variable/ivar2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | end 4 | 5 | class D < C 6 | def foo = (@x = :D) 7 | def x = @x 8 | end 9 | 10 | class E < D 11 | end 12 | 13 | class F < E 14 | end 15 | 16 | class G < F 17 | end 18 | 19 | ## assert 20 | class C 21 | end 22 | class D < C 23 | def foo: -> :D 24 | def x: -> :D 25 | end 26 | class E < D 27 | end 28 | class F < E 29 | end 30 | class G < F 31 | end 32 | 33 | ## update 34 | class C 35 | end 36 | 37 | class D < C 38 | def foo = (@x = :D) 39 | def x = @x 40 | end 41 | 42 | class E < D 43 | end 44 | 45 | class F < E 46 | end 47 | 48 | class G < F 49 | def foo = (@x = :G) 50 | end 51 | 52 | ## assert 53 | class C 54 | end 55 | class D < C 56 | def foo: -> :D 57 | def x: -> (:D | :G) 58 | end 59 | class E < D 60 | end 61 | class F < E 62 | end 63 | class G < F 64 | def foo: -> :G 65 | end 66 | 67 | ## update 68 | class C 69 | end 70 | 71 | class D < C 72 | def foo = (@x = :D) 73 | def x = @x 74 | end 75 | 76 | class E < D 77 | def foo = (@x = :E) 78 | end 79 | 80 | class F < E 81 | end 82 | 83 | class G < F 84 | def foo = (@x = :G) 85 | end 86 | 87 | ## assert 88 | class C 89 | end 90 | class D < C 91 | def foo: -> :D 92 | def x: -> (:D | :E | :G) 93 | end 94 | class E < D 95 | def foo: -> :E 96 | end 97 | class F < E 98 | end 99 | class G < F 100 | def foo: -> :G 101 | end 102 | 103 | ## update 104 | class C 105 | end 106 | 107 | class D < C 108 | def foo = (@x = :D) 109 | def x = @x 110 | end 111 | 112 | class E < D 113 | end 114 | 115 | class F < E 116 | end 117 | 118 | class G < F 119 | def foo = (@x = :G) 120 | end 121 | 122 | ## assert 123 | class C 124 | end 125 | class D < C 126 | def foo: -> :D 127 | def x: -> (:D | :G) 128 | end 129 | class E < D 130 | end 131 | class F < E 132 | end 133 | class G < F 134 | def foo: -> :G 135 | end 136 | 137 | ## update 138 | class C 139 | end 140 | 141 | class D < C 142 | def foo = (@x = :D) 143 | def x = @x 144 | end 145 | 146 | class E < D 147 | end 148 | 149 | class F < E 150 | def foo = (@x = :F) 151 | end 152 | 153 | class G < F 154 | def foo = (@x = :G) 155 | end 156 | 157 | ## assert 158 | class C 159 | end 160 | class D < C 161 | def foo: -> :D 162 | def x: -> (:D | :F | :G) 163 | end 164 | class E < D 165 | end 166 | class F < E 167 | def foo: -> :F 168 | end 169 | class G < F 170 | def foo: -> :G 171 | end 172 | 173 | ## update 174 | class C 175 | end 176 | 177 | class D < C 178 | def foo = (@x = :D) 179 | def x = @x 180 | end 181 | 182 | class E < D 183 | end 184 | 185 | class F < E 186 | end 187 | 188 | class G < F 189 | def foo = (@x = :G) 190 | end 191 | 192 | ## assert 193 | class C 194 | end 195 | class D < C 196 | def foo: -> :D 197 | def x: -> (:D | :G) 198 | end 199 | class E < D 200 | end 201 | class F < E 202 | end 203 | class G < F 204 | def foo: -> :G 205 | end 206 | 207 | ## update 208 | class C 209 | end 210 | 211 | class D < C 212 | def foo = (@x = :D) 213 | def x = @x 214 | end 215 | 216 | class E < D 217 | end 218 | 219 | class F < E 220 | def foo = (@x = :F) 221 | end 222 | 223 | class G < F 224 | def foo = (@x = :G) 225 | end 226 | 227 | ## assert 228 | class C 229 | end 230 | class D < C 231 | def foo: -> :D 232 | def x: -> (:D | :F | :G) 233 | end 234 | class E < D 235 | end 236 | class F < E 237 | def foo: -> :F 238 | end 239 | class G < F 240 | def foo: -> :G 241 | end 242 | 243 | ## update 244 | class C 245 | end 246 | 247 | class D < C 248 | def foo = (@x = :D) 249 | def x = @x 250 | end 251 | 252 | class E < D 253 | end 254 | 255 | class F < E 256 | def foo = (@x = :F) 257 | end 258 | 259 | class G < F 260 | end 261 | 262 | ## assert 263 | class C 264 | end 265 | class D < C 266 | def foo: -> :D 267 | def x: -> (:D | :F) 268 | end 269 | class E < D 270 | end 271 | class F < E 272 | def foo: -> :F 273 | end 274 | class G < F 275 | end 276 | -------------------------------------------------------------------------------- /scenario/variable/ivar3.rb: -------------------------------------------------------------------------------- 1 | ## update: test0.rb 2 | class C 3 | def foo = (@x = :C) 4 | def x = @x 5 | end 6 | 7 | class X 8 | class D < C 9 | end 10 | end 11 | 12 | class E < X::D 13 | def foo = (@x = :E) 14 | end 15 | 16 | ## assert: test0.rb 17 | class C 18 | def foo: -> :C 19 | def x: -> (:C | :E) 20 | end 21 | class X 22 | class X::D < C 23 | end 24 | end 25 | class E < X::D 26 | def foo: -> :E 27 | end 28 | 29 | ## update: test1.rb 30 | class X 31 | class C 32 | def foo = (@x = :XC) 33 | def x = @x 34 | end 35 | end 36 | 37 | ## assert: test0.rb 38 | class C 39 | def foo: -> :C 40 | def x: -> :C 41 | end 42 | class X 43 | class X::D < X::C 44 | end 45 | end 46 | class E < X::D 47 | def foo: -> :E 48 | end 49 | 50 | ## assert: test1.rb 51 | class X 52 | class X::C 53 | def foo: -> :XC 54 | def x: -> (:E | :XC) 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /scenario/variable/masgn-non-array.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check 3 | *ary = 42 4 | ary 5 | end 6 | 7 | ## assert 8 | class Object 9 | def check: -> Array[Integer] 10 | end 11 | 12 | ## update: test.rb 13 | def check 14 | a, *ary, z = 42 15 | [a, ary, z] 16 | end 17 | 18 | ## assert 19 | class Object 20 | def check: -> [Integer, Array[untyped], untyped] 21 | end 22 | -------------------------------------------------------------------------------- /scenario/variable/masgn.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def baz 3 | [1, 1.0, "str"] 4 | end 5 | 6 | def foo 7 | x, y, z, w = baz 8 | x 9 | end 10 | 11 | def bar 12 | x = nil 13 | 1.times do |_| 14 | x, y, z, w = baz 15 | end 16 | x 17 | end 18 | 19 | ## assert 20 | class Object 21 | def baz: -> [Integer, Float, String] 22 | def foo: -> Integer 23 | def bar: -> Integer? 24 | end 25 | 26 | ## update 27 | x, C, C::D::E, @iv, @@cv, $gv, ary[0], foo.bar = 1, 2, 3, 4, 5, 6, 7, 8 28 | -------------------------------------------------------------------------------- /scenario/variable/masgn2.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def test 3 | if rand < 0.5 4 | nil 5 | else 6 | [1, "str"] 7 | end 8 | end 9 | 10 | def foo 11 | a, b = test 12 | a 13 | end 14 | 15 | def bar 16 | a, b = test 17 | b 18 | end 19 | 20 | ## assert 21 | class Object 22 | def test: -> [Integer, String]? 23 | def foo: -> Integer? 24 | def bar: -> String 25 | end 26 | -------------------------------------------------------------------------------- /scenario/variable/masgn3.rb: -------------------------------------------------------------------------------- 1 | ## update: test.rb 2 | def check 3 | *ary = [:a, :b, :c, :d] 4 | ary 5 | end 6 | 7 | ## assert 8 | class Object 9 | def check: -> Array[:a | :b | :c | :d] 10 | end 11 | 12 | ## update: test.rb 13 | def check 14 | a, *ary, z = [:a, :b, :c, :d] 15 | [a, ary, z] 16 | end 17 | 18 | ## assert 19 | class Object 20 | def check: -> [:a, Array[:b | :c], :d] 21 | end 22 | 23 | ## update 24 | def check 25 | a, *, d = [:a, :b, :c, :d] 26 | [a, d] 27 | end 28 | 29 | ## assert 30 | class Object 31 | def check: -> [:a, :d] 32 | end 33 | 34 | ## update 35 | def check 36 | a, = [:a, :b, :c, :d] 37 | a 38 | end 39 | 40 | ## assert 41 | class Object 42 | def check: -> :a 43 | end 44 | -------------------------------------------------------------------------------- /scenario/variable/operator_write.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | $gv = 0 3 | $gv += 1 4 | class C 5 | D = 0 6 | D += 1 7 | @@cvar = "" 8 | @@cvar += "1" 9 | def get_lv 10 | lv = 0 11 | lv += 1 12 | lv 13 | end 14 | def set_iv 15 | @iv = 0 16 | @iv += 1 17 | end 18 | def get_iv = @iv 19 | def get_gv = $gv 20 | def set_cv 21 | @@cvar = "" 22 | @@cvar += "hoge" 23 | end 24 | def get_cv = @@cvar 25 | def get_index_asgn 26 | ary = [0] 27 | ary[0] += 1 28 | ary 29 | end 30 | def get_attr_asgn 31 | self.test_attr += 1 32 | end 33 | def test_attr = 0 34 | def test_attr=(x) 35 | x 36 | end 37 | end 38 | C::E = 0 39 | C::E += 1 40 | 41 | 42 | ## diagnostics 43 | ## assert 44 | class C 45 | C::D: Integer 46 | C::D: Integer 47 | def get_lv: -> Integer 48 | def set_iv: -> Integer 49 | def get_iv: -> Integer 50 | def get_gv: -> Integer 51 | def set_cv: -> String 52 | def get_cv: -> String 53 | def get_index_asgn: -> [Integer] 54 | def get_attr_asgn: -> Integer 55 | def test_attr: -> Integer 56 | def test_attr=: (Integer) -> Integer 57 | end 58 | C::E: Integer 59 | C::E: Integer 60 | -------------------------------------------------------------------------------- /scenario/variable/or_write.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | $gv ||= :GVar 3 | 4 | class C 5 | D ||= :ConstD 6 | @@cv ||= :CV0 7 | def get_lv 8 | lv = nil 9 | lv ||= :LVar 10 | lv 11 | end 12 | def set_iv 13 | @iv ||= :IVar 14 | end 15 | def get_iv = @iv 16 | def get_gv = $gv 17 | def set_cv 18 | @@cv ||= :CV1 19 | end 20 | def get_cv = @@cv 21 | def get_index_asgn 22 | ary = [nil] 23 | ary[0] ||= :IndexAsgn 24 | ary 25 | end 26 | def get_attr_asgn 27 | self.test_attr ||= :AttrAsgn 28 | end 29 | def test_attr = nil 30 | def test_attr=(x) 31 | x 32 | end 33 | end 34 | C::E ||= :ConstE 35 | 36 | ## diagnostics 37 | ## assert 38 | class C 39 | C::D: :ConstD 40 | def get_lv: -> :LVar 41 | def set_iv: -> :IVar 42 | def get_iv: -> :IVar 43 | def get_gv: -> :GVar 44 | def set_cv: -> (:CV0 | :CV1) 45 | def get_cv: -> (:CV0 | :CV1) 46 | def get_index_asgn: -> [:IndexAsgn?] 47 | def get_attr_asgn: -> :AttrAsgn 48 | def test_attr: -> nil 49 | def test_attr=: (:AttrAsgn) -> :AttrAsgn 50 | end 51 | C::E: :ConstE 52 | -------------------------------------------------------------------------------- /scenario/variable/special-vars.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def nth_group_of_last_match 3 | [$1, $2, $3, $4, $5, $6, $7, $8, $9, $10] 4 | end 5 | 6 | def back_reference 7 | $& 8 | end 9 | 10 | ## assert 11 | class Object 12 | def nth_group_of_last_match: -> [String, String, String, String, String, String, String, String, String, String] 13 | def back_reference: -> String 14 | end 15 | -------------------------------------------------------------------------------- /scenario/variable/uninitialized_ivar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | class C 3 | def foo 4 | @x 5 | end 6 | end 7 | 8 | ## assert 9 | class C 10 | def foo: -> untyped 11 | end 12 | -------------------------------------------------------------------------------- /scenario/variable/uninitialized_lvar.rb: -------------------------------------------------------------------------------- 1 | ## update 2 | def foo 3 | x = x.nil? 4 | x 5 | end 6 | 7 | ## assert 8 | class Object 9 | def foo: -> true 10 | end 11 | -------------------------------------------------------------------------------- /sig/polyfill.rbs: -------------------------------------------------------------------------------- 1 | class Object 2 | def pretty_print_instance_variables: -> Array[Symbol] 3 | end 4 | -------------------------------------------------------------------------------- /sig/typeprof.rbs: -------------------------------------------------------------------------------- 1 | module TypeProf 2 | class CodePosition 3 | def self.from_lsp: (untyped) -> instance 4 | end 5 | class CodeRange 6 | def self.from_node: (untyped) -> instance 7 | end 8 | 9 | module Core 10 | class Service 11 | def initialize: (Hash[untyped, untyped]) -> void 12 | def update_file: (String, String?) -> bool 13 | def update_rb_file: (String, String?) -> bool 14 | def update_rbs_file: (String, String?) -> bool 15 | def definitions: (String, CodePosition) -> Array[untyped] 16 | def type_definitions: (String, CodePosition) -> Array[untyped] 17 | def references: (String, CodePosition) -> Array[[String?, CodeRange]]? 18 | def hover: (String, CodePosition) -> Array[untyped] 19 | def code_lens: (String) { (CodeRange, String ) -> untyped } -> Array[untyped] 20 | def completion: (String, untyped, CodePosition) { (untyped) -> untyped } -> Array[untyped] 21 | def dump_declarations: (String) -> String 22 | def rename: (String, CodePosition) -> void 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/cli_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "helper" 2 | require "stringio" 3 | 4 | module TypeProf 5 | class CLITest < Test::Unit::TestCase 6 | def test_run(fixture_path, argv) 7 | output = StringIO.new(+"") 8 | Dir.chdir(File.join(__dir__, "fixtures", fixture_path)) do 9 | yield if block_given? 10 | cli = TypeProf::CLI::CLI.new(argv) 11 | cli.cli_options[:output] = output 12 | cli.core_options[:display_indicator] = false 13 | cli.run 14 | end 15 | output.string 16 | end 17 | 18 | def test_e2e_basic 19 | assert_equal(<<~END, test_run("basic", ["."])) 20 | # TypeProf #{ TypeProf::VERSION } 21 | 22 | # ./basic.rb 23 | class Object 24 | def foo: (String) -> String 25 | end 26 | END 27 | end 28 | 29 | def test_e2e_type_error 30 | assert_equal(<<~END, test_run("type_error", ["."])) 31 | # TypeProf #{ TypeProf::VERSION } 32 | 33 | # ./type_error.rb 34 | class Object 35 | def check: -> :ok 36 | end 37 | END 38 | 39 | assert_equal(<<~END, test_run("type_error", ["--show-error", "."])) 40 | # TypeProf #{ TypeProf::VERSION } 41 | 42 | # ./type_error.rb 43 | # (2,10)-(2,20):wrong type of arguments 44 | class Object 45 | def check: -> :ok 46 | end 47 | END 48 | end 49 | 50 | def test_e2e_syntax_error 51 | assert_equal(<<~END, test_run("syntax_error", ["."])) 52 | # TypeProf #{ TypeProf::VERSION } 53 | 54 | # failed to analyze: ./syntax_error.rb 55 | # failed to analyze: ./syntax_error.rbs 56 | END 57 | end 58 | 59 | def test_e2e_no_version 60 | assert_equal(<<~END, test_run("basic", ["--no-show-typeprof-version", "."])) 61 | # ./basic.rb 62 | class Object 63 | def foo: (String) -> String 64 | end 65 | END 66 | end 67 | 68 | def test_e2e_output_param_names 69 | assert_equal(<<~END, test_run("basic", ["--show-parameter-names", "."])) 70 | # TypeProf #{ TypeProf::VERSION } 71 | 72 | # ./basic.rb 73 | class Object 74 | def foo: (String n) -> String 75 | end 76 | END 77 | end 78 | 79 | def test_e2e_output_source_location 80 | assert_equal(<<~END, test_run("basic", ["--show-source-location", "."])) 81 | # TypeProf #{ TypeProf::VERSION } 82 | 83 | # ./basic.rb 84 | class Object 85 | # ./basic.rb:1:1 86 | def foo: (String) -> String 87 | end 88 | END 89 | end 90 | 91 | def test_e2e_rbs_collection 92 | # The "rbs collection install" command attempts to create a symlink, 93 | # which requires elevated privileges on Windows 94 | omit if RUBY_PLATFORM =~ /mswin|mingw/ 95 | 96 | exp = <<~END 97 | # TypeProf #{ TypeProf::VERSION } 98 | 99 | # test.rb 100 | class Object 101 | def check: -> :ok 102 | end 103 | END 104 | 105 | assert_equal(exp, test_run("rbs_collection_test", ["test.rb"]) do 106 | lock_path = RBS::Collection::Config.to_lockfile_path(Pathname("rbs_collection.yaml").expand_path) 107 | 108 | open(IO::NULL, "w") do |null_stdout| 109 | RBS::Collection::Installer.new(lockfile_path: lock_path, stdout: null_stdout).install_from_lockfile 110 | end 111 | end) 112 | end 113 | 114 | def test_lsp_options_with_lsp_mode 115 | assert_nothing_raised { TypeProf::CLI::CLI.new(["--lsp", "--stdio"]) } 116 | end 117 | 118 | def test_lsp_options_with_non_lsp_mode 119 | invalid_options = [ 120 | ["--stdio", "."], 121 | ["--port", "123456", "."], 122 | ] 123 | 124 | invalid_options.each do |argv| 125 | stdout, _stderr = capture_output do 126 | assert_raises(SystemExit) { TypeProf::CLI::CLI.new(argv) } 127 | end 128 | assert_equal("invalid option: lsp options with non-lsp mode\n", stdout) 129 | end 130 | end 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /test/code_range_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "helper" 2 | 3 | module TypeProf 4 | class CodeRangeTest < Test::Unit::TestCase 5 | def test_position 6 | p1 = CodePosition.new(1, 1) 7 | p2 = CodePosition.new(1, 2) 8 | p3 = CodePosition.new(2, 0) 9 | p4 = CodePosition.new(2, 0) 10 | assert_operator(p1, :<, p2) 11 | assert_operator(p1, :<, p3) 12 | assert_operator(p3, :==, p4) 13 | end 14 | 15 | def test_eq 16 | p0 = CodePosition.new(1, 0) 17 | p1 = CodePosition.new(1, 1) 18 | p2 = CodePosition.new(1, 2) 19 | 20 | cr0 = CodeRange.new(p0, p1) 21 | cr1 = CodeRange.new(p0, p1) 22 | cr2 = CodeRange.new(p0, p2) 23 | 24 | assert_equal(true, cr0 == cr1) 25 | assert_equal(false, cr0 == cr2) 26 | end 27 | 28 | def test_include? 29 | p0 = CodePosition.new(1, 0) 30 | p1 = CodePosition.new(1, 1) 31 | p2 = CodePosition.new(1, 2) 32 | p3 = CodePosition.new(2, 0) 33 | p4 = CodePosition.new(2, 1) 34 | 35 | cr = CodeRange.new(p1, p3) 36 | assert_equal(false, cr.include?(p0)) 37 | assert_equal(true, cr.include?(p2)) 38 | assert_equal(false, cr.include?(p4)) 39 | end 40 | 41 | def test_inspect 42 | p1 = CodePosition.new(1, 1) 43 | p2 = CodePosition.new(2, 2) 44 | cr = CodeRange.new(p1, p2) 45 | assert_equal("(1,1)-(2,2)", cr.inspect) 46 | end 47 | 48 | def test_to_lsp 49 | p1 = CodePosition.new(1, 1) 50 | p2 = CodePosition.new(2, 2) 51 | cr = CodeRange.new(p1, p2) 52 | assert_equal({ start: { line: 0, character: 1 }, end: { line: 1, character: 2 } }, cr.to_lsp) 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /test/diagnostic_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "helper" 2 | 3 | module TypeProf 4 | class DiagnosticTest < Test::Unit::TestCase 5 | class DummyNode 6 | def code_range 7 | nil 8 | end 9 | end 10 | 11 | def test_diagnostic 12 | diag = Diagnostic.new(DummyNode.new, :code_range, "test message") 13 | assert_nil diag.tags 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /test/fixtures/basic/basic.rb: -------------------------------------------------------------------------------- 1 | def foo(n) 2 | n 3 | end 4 | 5 | foo("str") 6 | -------------------------------------------------------------------------------- /test/fixtures/basic/typeprof.conf.json: -------------------------------------------------------------------------------- 1 | // Experimental TypeProf configuration 2 | 3 | // The format is completely tentative and subject to change 4 | // (including whether to use JSON with Comments or TOML or Ruby DSL or something else) 5 | { 6 | // The version of TypeProf; you need to specify "experimental" 7 | "typeprof_version": "experimental", 8 | 9 | // The directory containing RBS files that defines the interface between the analysis units 10 | "rbs_dir": "sig/", 11 | 12 | // The directories containing Ruby files to be analyzed by TypeProf 13 | // Each directory will be independently analyzed 14 | // (but currently, multiple analysis units are not supported yet) 15 | "analysis_unit_dirs": [ 16 | ".", 17 | // "lib/typeprof/lsp", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/.gitignore: -------------------------------------------------------------------------------- 1 | .gem_rbs_collection -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "my_dummy_gem", path: "dummy_gem_source/my_dummy_gem" 4 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: dummy_gem_source/my_dummy_gem 3 | specs: 4 | my_dummy_gem (1.0.0) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | 10 | PLATFORMS 11 | ruby 12 | x86_64-linux 13 | 14 | DEPENDENCIES 15 | my_dummy_gem! 16 | 17 | BUNDLED WITH 18 | 2.6.0.dev 19 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/dummy_gem_source/my_dummy_gem/lib/my_dummy_gem.rb: -------------------------------------------------------------------------------- 1 | def hello(name) 2 | "Hello, #{ name }" 3 | raise 4 | end 5 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/dummy_gem_source/my_dummy_gem/my_dummy_gem.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |spec| 2 | spec.name = "my_dummy_gem" 3 | spec.version = "1.0.0" 4 | spec.authors = ["Yusuke Endoh"] 5 | spec.email = ["mame@ruby-lang.org"] 6 | 7 | spec.summary = %q{A dummy gem for testing TypePRof} 8 | spec.description = %q{A dummy gem for testing TypePRof} 9 | spec.homepage = "https://github.com/ruby/typeprof" 10 | spec.license = "MIT" 11 | spec.required_ruby_version = Gem::Requirement.new(">= 3.3") 12 | 13 | spec.metadata["homepage_uri"] = spec.homepage 14 | spec.metadata["source_code_uri"] = "https://github.com/ruby/typeprof" 15 | 16 | # Specify which files should be added to the gem when it is released. 17 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 18 | spec.files = ["lib/my_dummy_gem.rb"] 19 | spec.executables = [] 20 | spec.require_paths = ["lib"] 21 | end 22 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/dummy_rbs_collection/my_dummy_gem/1.0/my_dummy_gem.rbs: -------------------------------------------------------------------------------- 1 | class MyDummyGem 2 | def hello: (String) -> :ok 3 | end -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/rbs_collection.lock.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | path: ".gem_rbs_collection" 3 | gems: 4 | - name: my_dummy_gem 5 | version: '1.0' 6 | source: 7 | type: local 8 | path: "./dummy_rbs_collection" 9 | gemfile_lock_path: Gemfile.lock 10 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/rbs_collection.yaml: -------------------------------------------------------------------------------- 1 | # Download sources 2 | sources: 3 | - type: local 4 | path: ./dummy_rbs_collection 5 | 6 | # A directory to install the downloaded RBSs 7 | path: .gem_rbs_collection 8 | 9 | gems: 10 | - name: my_dummy_gem 11 | -------------------------------------------------------------------------------- /test/fixtures/rbs_collection_test/test.rb: -------------------------------------------------------------------------------- 1 | require "my_dummy_gem" 2 | 3 | def check 4 | MyDummyGem.new.hello("mame") 5 | end 6 | -------------------------------------------------------------------------------- /test/fixtures/syntax_error/syntax_error.rb: -------------------------------------------------------------------------------- 1 | def foo 2 | -------------------------------------------------------------------------------- /test/fixtures/syntax_error/syntax_error.rbs: -------------------------------------------------------------------------------- 1 | class Foo -------------------------------------------------------------------------------- /test/fixtures/type_error/type_error.rb: -------------------------------------------------------------------------------- 1 | def check 2 | Foo.new.accept_int("str") 3 | end 4 | -------------------------------------------------------------------------------- /test/fixtures/type_error/type_error.rbs: -------------------------------------------------------------------------------- 1 | class Foo 2 | def accept_int: (Integer) -> :ok 3 | end -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | if ENV["COVERAGE"] 2 | require "simplecov" 3 | SimpleCov.start 4 | end 5 | 6 | require "test/unit" 7 | require_relative "../lib/typeprof" 8 | -------------------------------------------------------------------------------- /test/lsp/text_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../helper" 2 | 3 | module TypeProf::LSP 4 | class TextTest < Test::Unit::TestCase 5 | def r(row1, col1, row2, col2) 6 | { 7 | start: { line: row1, character: col1 }, 8 | end: { line: row2, character: col2 }, 9 | } 10 | end 11 | 12 | def test_text 13 | text = Text.new("test.rb", "foo", 0) 14 | assert_equal("foo", text.string) 15 | end 16 | 17 | def test_apply_changes1 18 | text = Text.new("test.rb", "abcde", 0) 19 | text.apply_changes([{ range: r(0, 1, 0, 4), text: "FOO" }], 0) 20 | assert_equal("aFOOe", text.string) 21 | text.apply_changes([{ range: r(0, 1, 0, 4), text: "" }], 0) 22 | assert_equal("ae", text.string) 23 | end 24 | 25 | def test_apply_changes2 26 | text = Text.new("test.rb", "abcde", 0) 27 | text.apply_changes([ 28 | { range: r(0, 1, 0, 2), text: "" }, 29 | { range: r(0, 1, 0, 2), text: "FOO" }, 30 | { range: r(0, 1, 0, 2), text: "" }, 31 | ], 0) 32 | assert_equal("aOOde", text.string) 33 | end 34 | 35 | def test_apply_changes3 36 | text = Text.new("test.rb", "abc\ndef\nghi", 0) 37 | text.apply_changes([{ range: r(0, 1, 1, 2), text: "FOO" }], 0) 38 | assert_equal("aFOOf\nghi", text.string) 39 | text.apply_changes([{ range: r(0, 1, 1, 2), text: "AAA\nBBB\nCCC" }], 0) 40 | assert_equal("aAAA\nBBB\nCCCi", text.string) 41 | end 42 | 43 | def test_apply_changes4 44 | text = Text.new("test.rb", "foo\nbar", 0) 45 | text.apply_changes([{ range: r(0, 0, 0, 3), text: "" }], 0) 46 | assert_equal("\nbar", text.string) 47 | text.apply_changes([{ range: r(0, 0, 1, 0), text: "" }], 0) 48 | assert_equal("bar", text.string) 49 | text.apply_changes([{ range: r(0, 3, 0, 3), text: "\n" }], 0) 50 | assert_equal("bar\n", text.string) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /test/scenario_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "helper" 2 | require_relative "scenario_compiler" 3 | 4 | slow = ENV["SLOW"] 5 | base_dir = File.join(File.dirname(__dir__)) 6 | scenarios = Dir.glob(File.join(base_dir, "scenario/**/*.rb")) 7 | scenarios = scenarios.reject {|path| path.start_with?(File.join(base_dir, "scenario/known-issues")) } 8 | scenarios = scenarios.map {|scenario| scenario.delete_prefix(base_dir + File::Separator) } 9 | ScenarioCompiler.new(scenarios, fast: !slow).run 10 | -------------------------------------------------------------------------------- /tool/dog_bench.rb: -------------------------------------------------------------------------------- 1 | require_relative "../lib/typeprof" 2 | include TypeProf::Core 3 | 4 | def main(core) 5 | t = Time.now 6 | core.genv.run_count = 0 7 | Dir.glob("lib/typeprof/**/*.rb", sort: true) do |path| 8 | next if path.start_with?("lib/typeprof/lsp") 9 | puts path 10 | core.update_rb_file(path, File.read(path)) 11 | end 12 | puts "Elapsed: #{ Time.now - t }" 13 | #GC.start 14 | #p ObjectSpace.each_object(TypeProf::Core::BasicVertex).to_a.size 15 | #p ObjectSpace.each_object(TypeProf::Core::Box).to_a.size 16 | 17 | h = Hash.new(0) 18 | core.genv.type_table.each {|(t,*),| h[t] += 1 } 19 | pp h 20 | end 21 | 22 | core = Service.new({}) 23 | if ARGV[0] == "pf2" 24 | require "pf2" 25 | Pf2.start(interval_ms: 1, time_mode: :wall, threads: [Thread.current]) 26 | main(core) 27 | File.write("dog_bench.pf2profile", Pf2.stop) 28 | else 29 | require "stackprof" 30 | StackProf.run(mode: :cpu, out: "dog_bench.stackprof.dump", raw: true) do 31 | main(core) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /tool/scenario_runner.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | 5 | require_relative "../test/scenario_compiler" 6 | 7 | ScenarioCompiler.new(ARGV[0] ? ARGV : ["t.rb"], output_declarations: true, check_diff: false).run 8 | -------------------------------------------------------------------------------- /typeprof.conf.jsonc: -------------------------------------------------------------------------------- 1 | // Experimental TypeProf configuration 2 | 3 | // The format is completely tentative and subject to change 4 | // (including whether to use JSON with Comments or TOML or Ruby DSL or something else) 5 | { 6 | // The version of TypeProf; you need to specify "experimental" 7 | "typeprof_version": "experimental", 8 | 9 | // The directory containing RBS files that defines the interface between the analysis units 10 | "rbs_dir": "sig/", 11 | 12 | // The directories containing Ruby files to be analyzed by TypeProf 13 | // Each directory will be independently analyzed 14 | "analysis_unit_dirs": [ 15 | "lib/typeprof/core/", 16 | "lib/typeprof/lsp" 17 | ], 18 | 19 | // Severity of diagnosis, selectable from "error", "warning", "info", "hint", and "none". 20 | // Currently, TypeProf reports many false positives, so it is recommended to use "hint" or "none". 21 | "diagnostic_severity": "warning" 22 | } 23 | -------------------------------------------------------------------------------- /typeprof.gemspec: -------------------------------------------------------------------------------- 1 | require_relative 'lib/typeprof/version' 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "typeprof" # temporal 5 | spec.version = TypeProf::VERSION 6 | spec.authors = ["Yusuke Endoh"] 7 | spec.email = ["mame@ruby-lang.org"] 8 | 9 | spec.summary = %q{TypeProf is a type analysis tool for Ruby code based on abstract interpretation} 10 | spec.description = <<~EOD 11 | TypeProf performs a type analysis of non-annotated Ruby code. 12 | 13 | It abstractly executes input Ruby code in a level of types instead of values, gathers what types are passed to and returned by methods, and prints the analysis result in RBS format, a standard type description format for Ruby 3.0. 14 | EOD 15 | spec.homepage = "https://github.com/ruby/typeprof" 16 | spec.license = "MIT" 17 | spec.required_ruby_version = Gem::Requirement.new(">= 3.3") 18 | 19 | spec.metadata["homepage_uri"] = spec.homepage 20 | spec.metadata["source_code_uri"] = "https://github.com/ruby/typeprof" 21 | 22 | # Specify which files should be added to the gem when it is released. 23 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 24 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do 25 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.devcontainer|.github|scenario|sig|test|tool)/}) } - [ ".gitignore", "Gemfile", "Gemfile.lock", "Rakefile", "typeprof.conf.json"] 26 | end 27 | spec.bindir = "bin" 28 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 29 | spec.require_paths = ["lib"] 30 | 31 | spec.add_runtime_dependency "rbs", ">= 3.6.0" 32 | end 33 | --------------------------------------------------------------------------------