steep 1.6.0 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/CHANGELOG.md +49 -0
- data/README.md +18 -0
- data/Rakefile +5 -0
- data/bin/output_test.rb +1 -0
- data/doc/narrowing.md +195 -0
- data/doc/shape.md +194 -0
- data/guides/src/gem-rbs-collection/gem-rbs-collection.md +7 -24
- data/guides/src/getting-started/getting-started.md +10 -11
- data/lib/steep/ast/ignore.rb +148 -0
- data/lib/steep/ast/types/factory.rb +27 -18
- data/lib/steep/ast/types/helper.rb +4 -0
- data/lib/steep/ast/types/intersection.rb +7 -0
- data/lib/steep/ast/types/proc.rb +14 -9
- data/lib/steep/ast/types/record.rb +7 -0
- data/lib/steep/ast/types/tuple.rb +7 -0
- data/lib/steep/ast/types/union.rb +7 -0
- data/lib/steep/cli.rb +6 -1
- data/lib/steep/diagnostic/ruby.rb +16 -0
- data/lib/steep/drivers/stats.rb +2 -2
- data/lib/steep/drivers/utils/driver_helper.rb +22 -11
- data/lib/steep/drivers/validate.rb +4 -2
- data/lib/steep/expectations.rb +2 -2
- data/lib/steep/interface/block.rb +1 -1
- data/lib/steep/interface/builder.rb +342 -358
- data/lib/steep/interface/function.rb +82 -11
- data/lib/steep/interface/method_type.rb +18 -10
- data/lib/steep/interface/shape.rb +69 -18
- data/lib/steep/interface/substitution.rb +4 -0
- data/lib/steep/node_helper.rb +30 -1
- data/lib/steep/project/dsl.rb +18 -21
- data/lib/steep/project/options.rb +39 -2
- data/lib/steep/project/pattern.rb +1 -2
- data/lib/steep/project.rb +11 -7
- data/lib/steep/rake_task.rb +132 -0
- data/lib/steep/server/change_buffer.rb +2 -2
- data/lib/steep/server/interaction_worker.rb +67 -11
- data/lib/steep/server/lsp_formatter.rb +2 -0
- data/lib/steep/server/worker_process.rb +3 -1
- data/lib/steep/services/completion_provider.rb +59 -26
- data/lib/steep/services/file_loader.rb +15 -19
- data/lib/steep/services/signature_help_provider.rb +37 -35
- data/lib/steep/services/type_check_service.rb +36 -8
- data/lib/steep/signature/validator.rb +185 -133
- data/lib/steep/source/ignore_ranges.rb +69 -0
- data/lib/steep/source.rb +10 -4
- data/lib/steep/subtyping/check.rb +50 -43
- data/lib/steep/subtyping/result.rb +6 -0
- data/lib/steep/subtyping/variable_variance.rb +3 -3
- data/lib/steep/test.rb +9 -0
- data/lib/steep/type_construction.rb +205 -309
- data/lib/steep/type_inference/block_params.rb +12 -4
- data/lib/steep/type_inference/case_when.rb +301 -0
- data/lib/steep/type_inference/context.rb +1 -1
- data/lib/steep/type_inference/logic_type_interpreter.rb +3 -2
- data/lib/steep/type_inference/method_params.rb +16 -0
- data/lib/steep/type_inference/send_args.rb +5 -2
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +25 -8
- data/steep.gemspec +5 -2
- metadata +12 -396
- data/.github/dependabot.yml +0 -22
- data/.github/workflows/ruby-windows.yml +0 -34
- data/.github/workflows/ruby.yml +0 -33
- data/.vscode/steep-shared.code-snippets +0 -41
- data/Gemfile +0 -14
- data/Gemfile.lock +0 -104
- data/Gemfile.steep +0 -0
- data/gemfile_steep/Gemfile +0 -3
- data/gemfile_steep/Gemfile.lock +0 -64
- data/rbs_collection.steep.lock.yaml +0 -106
- data/rbs_collection.steep.yaml +0 -23
- data/sig/shims/bundler.rbs +0 -3
- data/sig/shims/concurrent-ruby.rbs +0 -39
- data/sig/shims/exception.rbs +0 -4
- data/sig/shims/language-server_protocol.rbs +0 -450
- data/sig/shims/parser/comment.rbs +0 -33
- data/sig/shims/parser/nodes.rbs +0 -252
- data/sig/shims/parser/source/map.rbs +0 -146
- data/sig/shims/parser/source/range.rbs +0 -237
- data/sig/shims/parser.rbs +0 -59
- data/sig/shims/string.rbs +0 -4
- data/sig/shims/tagged_logging.rbs +0 -6
- data/sig/steep/annotation_parser.rbs +0 -60
- data/sig/steep/ast/annotation/collection.rbs +0 -78
- data/sig/steep/ast/annotation.rbs +0 -121
- data/sig/steep/ast/builtin.rbs +0 -69
- data/sig/steep/ast/node/type_application.rbs +0 -31
- data/sig/steep/ast/node/type_assertion.rbs +0 -32
- data/sig/steep/ast/types/any.rbs +0 -29
- data/sig/steep/ast/types/boolean.rbs +0 -31
- data/sig/steep/ast/types/bot.rbs +0 -29
- data/sig/steep/ast/types/class.rbs +0 -33
- data/sig/steep/ast/types/factory.rbs +0 -110
- data/sig/steep/ast/types/helper.rbs +0 -22
- data/sig/steep/ast/types/instance.rbs +0 -33
- data/sig/steep/ast/types/intersection.rbs +0 -38
- data/sig/steep/ast/types/literal.rbs +0 -35
- data/sig/steep/ast/types/logic.rbs +0 -83
- data/sig/steep/ast/types/name.rbs +0 -80
- data/sig/steep/ast/types/nil.rbs +0 -31
- data/sig/steep/ast/types/proc.rbs +0 -53
- data/sig/steep/ast/types/record.rbs +0 -37
- data/sig/steep/ast/types/self.rbs +0 -33
- data/sig/steep/ast/types/top.rbs +0 -29
- data/sig/steep/ast/types/tuple.rbs +0 -35
- data/sig/steep/ast/types/union.rbs +0 -38
- data/sig/steep/ast/types/var.rbs +0 -42
- data/sig/steep/ast/types/void.rbs +0 -29
- data/sig/steep/ast/types.rbs +0 -16
- data/sig/steep/cli.rbs +0 -55
- data/sig/steep/diagnostic/deprecated/else_on_exhaustive_case.rbs +0 -13
- data/sig/steep/diagnostic/deprecated/unknown_constant_assigned.rbs +0 -15
- data/sig/steep/diagnostic/helper.rbs +0 -15
- data/sig/steep/diagnostic/lsp_formatter.rbs +0 -36
- data/sig/steep/diagnostic/ruby.rbs +0 -695
- data/sig/steep/diagnostic/signature.rbs +0 -252
- data/sig/steep/drivers/annotations.rbs +0 -17
- data/sig/steep/drivers/check.rbs +0 -33
- data/sig/steep/drivers/checkfile.rbs +0 -27
- data/sig/steep/drivers/diagnostic_printer.rbs +0 -25
- data/sig/steep/drivers/init.rbs +0 -19
- data/sig/steep/drivers/langserver.rbs +0 -36
- data/sig/steep/drivers/print_project.rbs +0 -15
- data/sig/steep/drivers/stats.rbs +0 -47
- data/sig/steep/drivers/utils/driver_helper.rbs +0 -25
- data/sig/steep/drivers/utils/jobs_option.rbs +0 -19
- data/sig/steep/drivers/validate.rbs +0 -15
- data/sig/steep/drivers/vendor.rbs +0 -19
- data/sig/steep/drivers/watch.rbs +0 -27
- data/sig/steep/drivers/worker.rbs +0 -29
- data/sig/steep/equatable.rbs +0 -11
- data/sig/steep/expectations.rbs +0 -72
- data/sig/steep/index/rbs_index.rbs +0 -141
- data/sig/steep/index/signature_symbol_provider.rbs +0 -41
- data/sig/steep/index/source_index.rbs +0 -63
- data/sig/steep/interface/block.rbs +0 -41
- data/sig/steep/interface/builder.rbs +0 -166
- data/sig/steep/interface/function.rbs +0 -265
- data/sig/steep/interface/method_type.rbs +0 -105
- data/sig/steep/interface/shape.rbs +0 -61
- data/sig/steep/interface/substitution.rbs +0 -49
- data/sig/steep/interface/type_param.rbs +0 -43
- data/sig/steep/method_name.rbs +0 -30
- data/sig/steep/module_helper.rbs +0 -16
- data/sig/steep/node_helper.rbs +0 -78
- data/sig/steep/path_helper.rbs +0 -15
- data/sig/steep/project/dsl.rbs +0 -104
- data/sig/steep/project/options.rbs +0 -27
- data/sig/steep/project/pattern.rbs +0 -47
- data/sig/steep/project/target.rbs +0 -25
- data/sig/steep/project.rbs +0 -26
- data/sig/steep/range_extension.rbs +0 -7
- data/sig/steep/server/base_worker.rbs +0 -49
- data/sig/steep/server/change_buffer.rbs +0 -36
- data/sig/steep/server/delay_queue.rbs +0 -37
- data/sig/steep/server/interaction_worker.rbs +0 -80
- data/sig/steep/server/lsp_formatter.rbs +0 -63
- data/sig/steep/server/master.rbs +0 -299
- data/sig/steep/server/type_check_worker.rbs +0 -141
- data/sig/steep/server/worker_process.rbs +0 -97
- data/sig/steep/services/completion_provider.rbs +0 -251
- data/sig/steep/services/content_change.rbs +0 -37
- data/sig/steep/services/file_loader.rbs +0 -21
- data/sig/steep/services/goto_service.rbs +0 -106
- data/sig/steep/services/hover_provider/rbs.rbs +0 -47
- data/sig/steep/services/hover_provider/ruby.rbs +0 -127
- data/sig/steep/services/hover_provider/singleton_methods.rbs +0 -11
- data/sig/steep/services/path_assignment.rbs +0 -21
- data/sig/steep/services/signature_help_provider.rbs +0 -49
- data/sig/steep/services/signature_service.rbs +0 -156
- data/sig/steep/services/stats_calculator.rbs +0 -41
- data/sig/steep/services/type_check_service.rbs +0 -107
- data/sig/steep/services/type_name_completion.rbs +0 -135
- data/sig/steep/signature/validator.rbs +0 -85
- data/sig/steep/source.rbs +0 -102
- data/sig/steep/subtyping/cache.rbs +0 -17
- data/sig/steep/subtyping/check.rbs +0 -129
- data/sig/steep/subtyping/constraints.rbs +0 -111
- data/sig/steep/subtyping/relation.rbs +0 -63
- data/sig/steep/subtyping/result.rbs +0 -175
- data/sig/steep/subtyping/variable_variance.rbs +0 -25
- data/sig/steep/thread_waiter.rbs +0 -13
- data/sig/steep/type_construction.rbs +0 -567
- data/sig/steep/type_inference/block_params.rbs +0 -170
- data/sig/steep/type_inference/constant_env.rbs +0 -29
- data/sig/steep/type_inference/context.rbs +0 -214
- data/sig/steep/type_inference/context_array.rbs +0 -38
- data/sig/steep/type_inference/logic_type_interpreter.rbs +0 -108
- data/sig/steep/type_inference/method_call.rbs +0 -124
- data/sig/steep/type_inference/method_params.rbs +0 -127
- data/sig/steep/type_inference/multiple_assignment.rbs +0 -76
- data/sig/steep/type_inference/send_args.rbs +0 -243
- data/sig/steep/type_inference/type_env.rbs +0 -160
- data/sig/steep/type_inference/type_env_builder.rbs +0 -81
- data/sig/steep/typing.rbs +0 -75
- data/sig/steep.rbs +0 -36
- data/smoke/alias/Steepfile +0 -6
- data/smoke/alias/a.rb +0 -16
- data/smoke/alias/a.rbs +0 -10
- data/smoke/alias/b.rb +0 -6
- data/smoke/alias/c.rb +0 -8
- data/smoke/alias/test_expectations.yml +0 -96
- data/smoke/and/Steepfile +0 -6
- data/smoke/and/a.rb +0 -8
- data/smoke/and/test_expectations.yml +0 -29
- data/smoke/array/Steepfile +0 -6
- data/smoke/array/a.rb +0 -18
- data/smoke/array/b.rb +0 -12
- data/smoke/array/c.rb +0 -6
- data/smoke/array/test_expectations.yml +0 -103
- data/smoke/block/Steepfile +0 -6
- data/smoke/block/a.rb +0 -10
- data/smoke/block/a.rbs +0 -6
- data/smoke/block/b.rb +0 -13
- data/smoke/block/c.rb +0 -9
- data/smoke/block/c.rbs +0 -3
- data/smoke/block/d.rb +0 -11
- data/smoke/block/e.rb +0 -12
- data/smoke/block/e.rbs +0 -4
- data/smoke/block/test_expectations.yml +0 -133
- data/smoke/case/Steepfile +0 -6
- data/smoke/case/a.rb +0 -18
- data/smoke/case/test_expectations.yml +0 -47
- data/smoke/class/Steepfile +0 -6
- data/smoke/class/a.rb +0 -25
- data/smoke/class/a.rbs +0 -23
- data/smoke/class/b.rb +0 -5
- data/smoke/class/c.rb +0 -9
- data/smoke/class/f.rb +0 -10
- data/smoke/class/g.rb +0 -6
- data/smoke/class/h.rb +0 -19
- data/smoke/class/h.rbs +0 -6
- data/smoke/class/i.rb +0 -14
- data/smoke/class/i.rbs +0 -9
- data/smoke/class/test_expectations.yml +0 -117
- data/smoke/compact/Steepfile +0 -6
- data/smoke/compact/a.rb +0 -2
- data/smoke/compact/a.rbs +0 -5
- data/smoke/compact/b.rb +0 -2
- data/smoke/compact/test_expectations.yml +0 -18
- data/smoke/const/Steepfile +0 -6
- data/smoke/const/a.rb +0 -27
- data/smoke/const/b.rb +0 -7
- data/smoke/const/b.rbs +0 -5
- data/smoke/const/test_expectations.yml +0 -134
- data/smoke/diagnostics/Steepfile +0 -6
- data/smoke/diagnostics/a.rbs +0 -22
- data/smoke/diagnostics/argument_type_mismatch.rb +0 -1
- data/smoke/diagnostics/block_body_type_mismatch.rb +0 -1
- data/smoke/diagnostics/block_type_mismatch.rb +0 -3
- data/smoke/diagnostics/break_type_mismatch.rb +0 -1
- data/smoke/diagnostics/different_method_parameter_kind.rb +0 -9
- data/smoke/diagnostics/else_on_exhaustive_case.rb +0 -12
- data/smoke/diagnostics/incompatible_annotation.rb +0 -6
- data/smoke/diagnostics/incompatible_argument.rb +0 -1
- data/smoke/diagnostics/incompatible_assignment.rb +0 -8
- data/smoke/diagnostics/method_arity_mismatch.rb +0 -11
- data/smoke/diagnostics/method_body_type_mismatch.rb +0 -6
- data/smoke/diagnostics/method_definition_missing.rb +0 -2
- data/smoke/diagnostics/method_parameter_mismatch.rb +0 -10
- data/smoke/diagnostics/method_return_type_annotation_mismatch.rb +0 -7
- data/smoke/diagnostics/missing_keyword.rb +0 -1
- data/smoke/diagnostics/no_method.rb +0 -1
- data/smoke/diagnostics/proc_type_expected.rb +0 -3
- data/smoke/diagnostics/required_block_missing.rb +0 -1
- data/smoke/diagnostics/return_type_mismatch.rb +0 -6
- data/smoke/diagnostics/test_expectations.yml +0 -591
- data/smoke/diagnostics/unexpected_block_given.rb +0 -1
- data/smoke/diagnostics/unexpected_dynamic_method.rb +0 -3
- data/smoke/diagnostics/unexpected_jump.rb +0 -4
- data/smoke/diagnostics/unexpected_jump_value.rb +0 -3
- data/smoke/diagnostics/unexpected_keyword.rb +0 -1
- data/smoke/diagnostics/unexpected_splat.rb +0 -1
- data/smoke/diagnostics/unexpected_yield.rb +0 -6
- data/smoke/diagnostics/unknown_constant_assigned.rb +0 -7
- data/smoke/diagnostics/unresolved_overloading.rb +0 -1
- data/smoke/diagnostics/unsupported_syntax.rb +0 -2
- data/smoke/diagnostics-rbs/Steepfile +0 -8
- data/smoke/diagnostics-rbs/duplicated-method-definition.rbs +0 -20
- data/smoke/diagnostics-rbs/generic-parameter-mismatch.rbs +0 -7
- data/smoke/diagnostics-rbs/inherit-module.rbs +0 -2
- data/smoke/diagnostics-rbs/invalid-method-overload.rbs +0 -3
- data/smoke/diagnostics-rbs/invalid-type-application.rbs +0 -7
- data/smoke/diagnostics-rbs/invalid_variance_annotation.rbs +0 -3
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +0 -6
- data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/recursive-alias.rbs +0 -5
- data/smoke/diagnostics-rbs/recursive-class.rbs +0 -8
- data/smoke/diagnostics-rbs/recursive-type-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/superclass-mismatch.rbs +0 -7
- data/smoke/diagnostics-rbs/test_expectations.yml +0 -300
- data/smoke/diagnostics-rbs/unknown-method-alias.rbs +0 -3
- data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +0 -5
- data/smoke/diagnostics-rbs/unknown-type-name.rbs +0 -13
- data/smoke/diagnostics-rbs-duplicated/Steepfile +0 -6
- data/smoke/diagnostics-rbs-duplicated/a.rbs +0 -5
- data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +0 -13
- data/smoke/diagnostics-ruby-unsat/Steepfile +0 -6
- data/smoke/diagnostics-ruby-unsat/a.rbs +0 -3
- data/smoke/diagnostics-ruby-unsat/test_expectations.yml +0 -27
- data/smoke/diagnostics-ruby-unsat/unsatisfiable_constraint.rb +0 -6
- data/smoke/dstr/Steepfile +0 -6
- data/smoke/dstr/a.rb +0 -5
- data/smoke/dstr/test_expectations.yml +0 -13
- data/smoke/ensure/Steepfile +0 -6
- data/smoke/ensure/a.rb +0 -18
- data/smoke/ensure/test_expectations.yml +0 -62
- data/smoke/enumerator/Steepfile +0 -6
- data/smoke/enumerator/a.rb +0 -6
- data/smoke/enumerator/b.rb +0 -17
- data/smoke/enumerator/test_expectations.yml +0 -47
- data/smoke/extension/Steepfile +0 -6
- data/smoke/extension/a.rb +0 -10
- data/smoke/extension/a.rbs +0 -13
- data/smoke/extension/b.rb +0 -10
- data/smoke/extension/c.rb +0 -9
- data/smoke/extension/d.rb +0 -2
- data/smoke/extension/e.rb +0 -2
- data/smoke/extension/e.rbs +0 -7
- data/smoke/extension/f.rb +0 -2
- data/smoke/extension/f.rbs +0 -3
- data/smoke/extension/test_expectations.yml +0 -73
- data/smoke/hash/Steepfile +0 -6
- data/smoke/hash/a.rb +0 -17
- data/smoke/hash/a.rbs +0 -8
- data/smoke/hash/b.rb +0 -6
- data/smoke/hash/c.rb +0 -15
- data/smoke/hash/d.rb +0 -5
- data/smoke/hash/e.rb +0 -1
- data/smoke/hash/e.rbs +0 -3
- data/smoke/hash/f.rb +0 -11
- data/smoke/hash/test_expectations.yml +0 -81
- data/smoke/hello/Steepfile +0 -6
- data/smoke/hello/hello.rb +0 -11
- data/smoke/hello/hello.rbs +0 -7
- data/smoke/hello/test_expectations.yml +0 -25
- data/smoke/if/Steepfile +0 -6
- data/smoke/if/a.rb +0 -20
- data/smoke/if/test_expectations.yml +0 -34
- data/smoke/implements/Steepfile +0 -6
- data/smoke/implements/a.rb +0 -12
- data/smoke/implements/a.rbs +0 -6
- data/smoke/implements/b.rb +0 -13
- data/smoke/implements/b.rbs +0 -12
- data/smoke/implements/test_expectations.yml +0 -23
- data/smoke/initialize/Steepfile +0 -6
- data/smoke/initialize/a.rb +0 -12
- data/smoke/initialize/a.rbs +0 -3
- data/smoke/initialize/test_expectations.yml +0 -1
- data/smoke/integer/Steepfile +0 -6
- data/smoke/integer/a.rb +0 -26
- data/smoke/integer/test_expectations.yml +0 -110
- data/smoke/interface/Steepfile +0 -6
- data/smoke/interface/a.rb +0 -12
- data/smoke/interface/a.rbs +0 -12
- data/smoke/interface/test_expectations.yml +0 -23
- data/smoke/kwbegin/Steepfile +0 -6
- data/smoke/kwbegin/a.rb +0 -7
- data/smoke/kwbegin/test_expectations.yml +0 -17
- data/smoke/lambda/Steepfile +0 -6
- data/smoke/lambda/a.rb +0 -10
- data/smoke/lambda/test_expectations.yml +0 -17
- data/smoke/literal/Steepfile +0 -6
- data/smoke/literal/a.rb +0 -11
- data/smoke/literal/b.rb +0 -7
- data/smoke/literal/literal_methods.rbs +0 -4
- data/smoke/literal/test_expectations.yml +0 -106
- data/smoke/map/Steepfile +0 -6
- data/smoke/map/a.rb +0 -5
- data/smoke/map/test_expectations.yml +0 -1
- data/smoke/method/Steepfile +0 -6
- data/smoke/method/a.rb +0 -21
- data/smoke/method/a.rbs +0 -4
- data/smoke/method/b.rb +0 -25
- data/smoke/method/c.rb +0 -5
- data/smoke/method/d.rb +0 -1
- data/smoke/method/d.rbs +0 -3
- data/smoke/method/test_expectations.yml +0 -121
- data/smoke/module/Steepfile +0 -6
- data/smoke/module/a.rb +0 -19
- data/smoke/module/a.rbs +0 -16
- data/smoke/module/b.rb +0 -6
- data/smoke/module/c.rb +0 -22
- data/smoke/module/d.rb +0 -4
- data/smoke/module/e.rb +0 -13
- data/smoke/module/f.rb +0 -11
- data/smoke/module/test_expectations.yml +0 -75
- data/smoke/regexp/Steepfile +0 -6
- data/smoke/regexp/a.rb +0 -109
- data/smoke/regexp/b.rb +0 -79
- data/smoke/regexp/test_expectations.yml +0 -615
- data/smoke/regression/Steepfile +0 -6
- data/smoke/regression/array.rb +0 -7
- data/smoke/regression/block_param_split.rb +0 -7
- data/smoke/regression/block_param_split.rbs +0 -3
- data/smoke/regression/empty_yield.rb +0 -5
- data/smoke/regression/empty_yield.rbs +0 -3
- data/smoke/regression/enumerator_product.rb +0 -1
- data/smoke/regression/fun.rb +0 -8
- data/smoke/regression/fun.rbs +0 -4
- data/smoke/regression/hash.rb +0 -7
- data/smoke/regression/hello world.rb +0 -1
- data/smoke/regression/issue_328.rb +0 -1
- data/smoke/regression/issue_328.rbs +0 -0
- data/smoke/regression/issue_332.rb +0 -11
- data/smoke/regression/issue_332.rbs +0 -19
- data/smoke/regression/issue_372.rb +0 -8
- data/smoke/regression/issue_372.rbs +0 -4
- data/smoke/regression/lambda.rb +0 -3
- data/smoke/regression/masgn.rb +0 -4
- data/smoke/regression/poly_new.rb +0 -2
- data/smoke/regression/poly_new.rbs +0 -4
- data/smoke/regression/range.rb +0 -5
- data/smoke/regression/set_divide.rb +0 -12
- data/smoke/regression/test_expectations.yml +0 -120
- data/smoke/regression/thread.rb +0 -7
- data/smoke/rescue/Steepfile +0 -6
- data/smoke/rescue/a.rb +0 -48
- data/smoke/rescue/test_expectations.yml +0 -79
- data/smoke/self/Steepfile +0 -6
- data/smoke/self/a.rb +0 -21
- data/smoke/self/a.rbs +0 -4
- data/smoke/self/test_expectations.yml +0 -23
- data/smoke/skip/Steepfile +0 -6
- data/smoke/skip/skip.rb +0 -13
- data/smoke/skip/test_expectations.yml +0 -23
- data/smoke/stdout/Steepfile +0 -6
- data/smoke/stdout/a.rb +0 -8
- data/smoke/stdout/a.rbs +0 -7
- data/smoke/stdout/test_expectations.yml +0 -1
- data/smoke/super/Steepfile +0 -6
- data/smoke/super/a.rb +0 -30
- data/smoke/super/a.rbs +0 -10
- data/smoke/super/test_expectations.yml +0 -69
- data/smoke/toplevel/Steepfile +0 -6
- data/smoke/toplevel/a.rb +0 -3
- data/smoke/toplevel/a.rbs +0 -3
- data/smoke/toplevel/test_expectations.yml +0 -15
- data/smoke/tsort/Steepfile +0 -7
- data/smoke/tsort/a.rb +0 -12
- data/smoke/tsort/test_expectations.yml +0 -1
- data/smoke/type_case/Steepfile +0 -6
- data/smoke/type_case/a.rb +0 -24
- data/smoke/type_case/test_expectations.yml +0 -58
- data/smoke/unexpected/Steepfile +0 -6
- data/smoke/unexpected/test_expectations.yml +0 -13
- data/smoke/unexpected/unexpected.rbs +0 -3
- data/smoke/yield/Steepfile +0 -6
- data/smoke/yield/a.rb +0 -15
- data/smoke/yield/b.rb +0 -6
- data/smoke/yield/test_expectations.yml +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6031a713ec97be707b33a667121cba53ba966e30c0949c1070c62ccf4c698596
|
4
|
+
data.tar.gz: 01cd81e06eb1228a4b01070e0f6a12098fe10ee2cfe7620434a629f70e504005
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abfac9447afb1c68ba1702738f1ffd67c9b2cddc860a84a4552b963eafd3e9936987c2085d25b565b8834bc70be49bf5271daa28ac02926db12a5d056cc0780b
|
7
|
+
data.tar.gz: '0871a287d3bc466c58a9106def0ed944e682c862f5ab30d849cfd9dfdcbd9aefb49b376791c6a61211f0cfefef000d05f62e7b0ce3a5045faf9f2f9a39eadc0d'
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,54 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.7.1 (2024-06-12)
|
4
|
+
|
5
|
+
### Type checker core
|
6
|
+
|
7
|
+
* Fix subtyping issues ([#1165](https://github.com/soutaro/steep/pull/1165))
|
8
|
+
|
9
|
+
## 1.7.0 (2024-06-07)
|
10
|
+
|
11
|
+
### Type checker core
|
12
|
+
|
13
|
+
* Implement untyped function params ([#1101](https://github.com/soutaro/steep/pull/1101))
|
14
|
+
* Fix method call type narrowing with`||` operator ([#1085](https://github.com/soutaro/steep/pull/1085))
|
15
|
+
* Refactor `Interface::Builder` ([#1081](https://github.com/soutaro/steep/pull/1081))
|
16
|
+
* Fix UnexpectedError with unnamed arguments ([#1041](https://github.com/soutaro/steep/pull/1041))
|
17
|
+
* Abort if subtyping fails to (possible) infinite loop ([#1055](https://github.com/soutaro/steep/pull/1055))
|
18
|
+
* Ignore diagnostics by `steep:ignore` comment ([#1034](https://github.com/soutaro/steep/pull/1034))
|
19
|
+
* Make defined? accept any type ([#1031](https://github.com/soutaro/steep/pull/1031))
|
20
|
+
* Refactor case-when syntax ([#999](https://github.com/soutaro/steep/pull/999))
|
21
|
+
* Update `Steep::Subtyping::Check#check` types ([#972](https://github.com/soutaro/steep/pull/972))
|
22
|
+
|
23
|
+
### Commandline tool
|
24
|
+
|
25
|
+
* Improve wildcard handling in pattern matching for directory paths ([#1121](https://github.com/soutaro/steep/pull/1121))
|
26
|
+
* Fix issue with wildcard expansion in FileLoader ([#1113](https://github.com/soutaro/steep/pull/1113))
|
27
|
+
* Avoid unnecessary calling `RBS::Location#to_s` on debug log ([#1092](https://github.com/soutaro/steep/pull/1092))
|
28
|
+
* Better recovery from collection problems ([#987](https://github.com/soutaro/steep/pull/987))
|
29
|
+
* Handle absolute path ([#975](https://github.com/soutaro/steep/pull/975))
|
30
|
+
* Default to check the entire current directory when there is no `Steepfile` ([#968](https://github.com/soutaro/steep/pull/968))
|
31
|
+
|
32
|
+
### Language server
|
33
|
+
|
34
|
+
* Fix variable untyped hover issue in rescue clause ([#1147](https://github.com/soutaro/steep/pull/1147))
|
35
|
+
* Handle `$/file/reset` request in interaction worker ([#1122](https://github.com/soutaro/steep/pull/1122))
|
36
|
+
* Skip pending UI jobs ([#1035](https://github.com/soutaro/steep/pull/1035))
|
37
|
+
* Fix no method error ([#1040](https://github.com/soutaro/steep/pull/1040))
|
38
|
+
* Implement completion for comments ([#1039](https://github.com/soutaro/steep/pull/1039))
|
39
|
+
* Fix signature help ([#1038](https://github.com/soutaro/steep/pull/1038))
|
40
|
+
|
41
|
+
### Miscellaneous
|
42
|
+
|
43
|
+
* Revise rake tasks ([#1156](https://github.com/soutaro/steep/pull/1156))
|
44
|
+
* Update `steep.gemspec` ([#1155](https://github.com/soutaro/steep/pull/1155))
|
45
|
+
* Add `Steep::RakeTask` ([#995](https://github.com/soutaro/steep/pull/995))
|
46
|
+
* Stop to distribute sig dir ([#1144](https://github.com/soutaro/steep/pull/1144))
|
47
|
+
* Update gem-rbs-collection.md ([#1127](https://github.com/soutaro/steep/pull/1127))
|
48
|
+
* Add shape docs ([#1089](https://github.com/soutaro/steep/pull/1089))
|
49
|
+
* Ignore smoke tests when packaging gem ([#962](https://github.com/soutaro/steep/pull/962))
|
50
|
+
* Fix setup for Ruby 3.3 ([#1000](https://github.com/soutaro/steep/pull/1000))
|
51
|
+
|
3
52
|
## master
|
4
53
|
|
5
54
|
## 1.6.0 (2023-11-09)
|
data/README.md
CHANGED
@@ -219,6 +219,24 @@ Steep implements some of the Language Server Protocol features.
|
|
219
219
|
|
220
220
|
Other LSP supporting tools may work with Steep where it starts the server as `steep langserver`.
|
221
221
|
|
222
|
+
## Rake Tasks
|
223
|
+
|
224
|
+
Steep comes with a set of configurable Rake tasks.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
# Rakefile
|
228
|
+
|
229
|
+
require "steep/rake_task"
|
230
|
+
Steep::RakeTask.new do |t|
|
231
|
+
t.check.severity_level = :error
|
232
|
+
t.watch.verbose
|
233
|
+
end
|
234
|
+
|
235
|
+
task default: [:steep]
|
236
|
+
```
|
237
|
+
|
238
|
+
Use `bundle exec rake -T` to see all available tasks.
|
239
|
+
|
222
240
|
## Development
|
223
241
|
|
224
242
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/Rakefile
CHANGED
@@ -188,6 +188,11 @@ NOTES
|
|
188
188
|
milestone = "Steep #{major}.#{minor}.x"
|
189
189
|
end
|
190
190
|
|
191
|
+
if pre =~ /dev/
|
192
|
+
puts "🔍 Skipping `Released` tags because `dev` release: `#{pre}`"
|
193
|
+
next
|
194
|
+
end
|
195
|
+
|
191
196
|
puts "🔍 Finding pull requests that is associated to milestone `#{milestone}`..."
|
192
197
|
|
193
198
|
command = [
|
data/bin/output_test.rb
CHANGED
data/doc/narrowing.md
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
# Narrowing Implementation
|
2
|
+
|
3
|
+
> This is an internal doc for Steep developers. [Narrowing guide](../guides/narrowing/narrowing.md) is for users.
|
4
|
+
|
5
|
+
The challenge is Ruby has special type predicate methods that should be supported by type checkers. `#nil?` is used instead of `unless` statement to test if a value is a `nil` or not. `#is_a?` or `#===` are used to confirm if an object is an instance of a class. Negation and equality are implemented as methods -- `#!` and `#==`.
|
6
|
+
|
7
|
+
Steep supports those methods by introducing special types for those methods.
|
8
|
+
|
9
|
+
```rbs
|
10
|
+
# This is not a valid RBS type definition.
|
11
|
+
# Steep implements a transformation from valid RBS syntax to those special types.
|
12
|
+
module Kernel
|
13
|
+
def nil?: () -> RECEIVER_IS_NIL
|
14
|
+
|
15
|
+
def is_a?: (Class klass) -> RECEIVER_IS_ARG
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
When type checking a conditional resulted in `RECEIVER_IS_NIL` type, the type checker overrides the type of the expressions inside the *then* and *else* clauses.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
x = [1, ""].sample # The type of `x` is `String | Integer | nil`
|
23
|
+
|
24
|
+
unless x.is_a?(String) # 1. The condition expression has `RECEIVER_IS_NIL`
|
25
|
+
x.upcase # 2. Steep overrides the type of `x` to `String` in *then* clause
|
26
|
+
else
|
27
|
+
# 3. Steep overrides the type of `x` to `Integer | nil` in *else* clause
|
28
|
+
end
|
29
|
+
```
|
30
|
+
## Logical types
|
31
|
+
|
32
|
+
We extend *type* with *logical types* as follows:
|
33
|
+
|
34
|
+
```
|
35
|
+
type ::= ...
|
36
|
+
| NOT # Negation of type of receiver
|
37
|
+
| RECEIVER_IS_NIL # Receiver is nil when it evaluates to truthy
|
38
|
+
| RECEIVER_IS_NOT_NIL # Receiver is not nil when it evaluates to truthy
|
39
|
+
| RECEIVER_IS_ARG # Receiver is an instance of argument when it evaluates to truthy
|
40
|
+
| ARG_IS_RECEIVER # Argument is an instance of receiver when it evaluates to truthy
|
41
|
+
| ARG_EQUALS_RECEIVER # Argument is equal to receiver when it evaluates to truthy
|
42
|
+
| ENV(original_type, truthy_env, falsy_env) # Two type environments for truthy and falsy
|
43
|
+
```
|
44
|
+
### ENV type
|
45
|
+
|
46
|
+
`ENV` looks a bit different from others because it takes arguments. The type is used for `and` and `or`.
|
47
|
+
|
48
|
+
Consider the example with local variables `x` and `y` where both of them have type `String?`.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
(x && y) && (x + y) # Parens added for ease of reading
|
52
|
+
```
|
53
|
+
|
54
|
+
The type of the whole expression is `String?`. When `x` or `y` is `nil`, it evaluates to `nil`. If both of `x` and `y` is a `String`, `x + y` evaluates to `String` because of the definition of `String#+`.
|
55
|
+
|
56
|
+
The type narrowing starts with the top expression.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
(...) && (x + y)
|
60
|
+
```
|
61
|
+
|
62
|
+
It immediately type checks the left hand side, but with *conditional mode*. Conditional mode is a special flag that the type checking result should keep as many of the environments as possible.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
x && y
|
66
|
+
```
|
67
|
+
|
68
|
+
Going down again, it gets a typing `x: String?` and `y: String?`. It runs a type narrowing, to obtain a result both of `x` and `y` are `String` for truthy result, both of `x` and `y` are `String?` for falsy result. The two environments should be propagated to the upper node, because the parent node is also `&&` which is a subject of type narrowing. So, it returns an `ENV` type, `String?` for original type, `{ x: String, y: String }` for truthy result, and `{ x: String?, y: String? }` for falsy result.
|
69
|
+
|
70
|
+
Going up to the outer `&&` expression. The left hand side has `ENV` type, and then the right hand side is type checked based on the truthy environment (because of the semantics of `&&` expression.) Both `x` and `y` are `String` and it type checks. The type of the whole expression union of `String` and the falsy part of the original type -- `nil`.
|
71
|
+
## Union type partition
|
72
|
+
|
73
|
+
We introduce *partition* function for union types. It returns a pair of two types -- truthy parts and falsy parts. We need a slightly different variant for *non-nil* partition to support safe-navigation-operator.
|
74
|
+
|
75
|
+
```
|
76
|
+
Pt(T) -> T? ⨉ T? # Truthy partition
|
77
|
+
Pn(T) -> T? ⨉ T? # Non-nil partition
|
78
|
+
```
|
79
|
+
|
80
|
+
Both return a pair of optional types for non-falsy/non-nil types.
|
81
|
+
|
82
|
+
```
|
83
|
+
Pt(false?) -> ∅ ⨉ false?
|
84
|
+
Pn(false) -> false ⨉ ∅
|
85
|
+
```
|
86
|
+
|
87
|
+
Note that we cannot partition non-regular recursive types, but that types are prohibited in RBS.
|
88
|
+
## Type environment
|
89
|
+
|
90
|
+
Type environment is a mapping from local variables to their types. It's extended in Steep to support overriding type of *pure* expressions.
|
91
|
+
|
92
|
+
```
|
93
|
+
E ::= ∅
|
94
|
+
| x : T, E # Type of a local variable -- `x`
|
95
|
+
| p : T, E # Type of a pure expression -- `p`
|
96
|
+
```
|
97
|
+
|
98
|
+
Pure expressions are defined recursively as following:
|
99
|
+
|
100
|
+
* *Value expressions* are pure
|
101
|
+
* Call expressions of *pure methods* with pure arguments are pure
|
102
|
+
|
103
|
+
Note that expression purity depends on the result of type checking of the expression because it requires to detect if a method call is *pure* or not.
|
104
|
+
## Logic type interpreter
|
105
|
+
Logic type interpreter is an additional layer to support type narrowing. It is a function that takes an expression and it's typing, and returns a pair of type environments -- one for the case the value of the expr is *truthy* and another for the case the value is *falsy*.
|
106
|
+
|
107
|
+
```
|
108
|
+
I(expr : T) -> E ⨉ E
|
109
|
+
```
|
110
|
+
|
111
|
+
It takes account of assignments to local variables.
|
112
|
+
|
113
|
+
```
|
114
|
+
I(x = y : String?) -> { x: String, y: String } ⨉ { x: nil, y: nil }
|
115
|
+
```
|
116
|
+
|
117
|
+
It also calculates the reachability to truthy and falsy results which can be used to detect unreachable branches.
|
118
|
+
## Narrowing syntaxes
|
119
|
+
### Simple conditionals -- `if`, `while`, `and`, ...
|
120
|
+
Type checking those syntaxes are simple. It type checks the condition expression with conditional mode, passes the expression to logic type interpreter, uses the type environments to type check then and else clauses.
|
121
|
+
|
122
|
+
Steep also reports unreachable branch issues based on the reachability calculated by logic type interpreter.
|
123
|
+
### `case-when`
|
124
|
+
The easier case is if `case-when` doesn't have a node just after `case` token.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
case
|
128
|
+
when x == 1
|
129
|
+
...
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
This is the same with simple conditionals.
|
134
|
+
|
135
|
+
The difficult case is if `case-when` syntax has a node.
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
case foo()
|
139
|
+
when Integer
|
140
|
+
...
|
141
|
+
when String
|
142
|
+
...
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
Ruby uses the `===` operator to test if the value of `foo()` matches the condition, while we don't want to type check `foo()` calls every time. It may be a pure expression, and we can give better type narrowing using the *falsy* results of predecessor `when` clauses.
|
147
|
+
|
148
|
+
So, we transform the condition expression given to the logic type interpreter to value form.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
__case_when:x01jg9__ = foo()
|
152
|
+
if Integer === __case_when:x01jg9__
|
153
|
+
...
|
154
|
+
elsif String === __case_when:x01jg9__
|
155
|
+
...
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
It generates a fresh local variable and assigns the expression to it. Uses the variable inside the patterns.
|
160
|
+
|
161
|
+
We also need to propagate the type of local variables which are included in the expression.
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
case x = foo()
|
165
|
+
when Integer
|
166
|
+
x.abs # x should be Integer
|
167
|
+
when String
|
168
|
+
x.upcase # x should be String
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
The local variable insertion is done at the outermost non-assignment position to support the local variable propagation.
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
__case_when:x01jg9__ = foo()
|
176
|
+
if Integer === (x = __case_when:x01jg9__)
|
177
|
+
...
|
178
|
+
elsif String === (x = __case_when:x01jg9__)
|
179
|
+
...
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
The last trick to type check case-when is *pure call* narrowing in the bodies.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
__case_when:x01jg9__ = foo()
|
187
|
+
if Integer === (x = __case_when:x01jg9__)
|
188
|
+
foo.abs
|
189
|
+
elsif String === (x = __case_when:x01jg9__)
|
190
|
+
foo.upcase
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
To support this, we propagate the type of the fresh local variable to the type of right hand side expression, if it's a pure call.
|
195
|
+
|
data/doc/shape.md
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
# Shapes
|
2
|
+
|
3
|
+
A *shape* is a data structure, which contains the set of available methods and their types, which is associated with a type. Steep uses shapes to type check method calls -- it calculates the shape of the type of the receiver, checks if the called method is defined on the shape and the arguments are compatible with the method, and calculates the return type.
|
4
|
+
|
5
|
+
Assume an interface `_Foo` is defined as follows:
|
6
|
+
|
7
|
+
```rbs
|
8
|
+
interface _Foo
|
9
|
+
def foo: () -> String
|
10
|
+
|
11
|
+
def bar: () -> self
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
The shape of `_Foo` will be the following:
|
16
|
+
|
17
|
+
```
|
18
|
+
Shape (_Foo) {
|
19
|
+
foo: () -> String,
|
20
|
+
bar: () -> _Foo
|
21
|
+
}
|
22
|
+
```
|
23
|
+
|
24
|
+
Note that the `self` type in the example is resolved to `_Foo` during shape calculation.
|
25
|
+
|
26
|
+
The shape calculation of an object is straightforward. Calculate a `RBS::Definition` of a class singleton/instance, or an interface, and translate the data structure to a `Shape` object. But there are a few things to consider.
|
27
|
+
|
28
|
+
## Tuple, record, and proc types
|
29
|
+
|
30
|
+
The shape of tuple, record, or proc types are based on their base types -- Array, Hash, or Proc classes --, but with specialized method types.
|
31
|
+
|
32
|
+
```
|
33
|
+
Shape ([Integer, String]) {
|
34
|
+
[]: (0) -> Integer
|
35
|
+
| (1) -> String
|
36
|
+
| (Integer) -> (Integer | String)
|
37
|
+
...
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
The specialization is implemented as a part of shape calculation.
|
42
|
+
|
43
|
+
## Special methods
|
44
|
+
|
45
|
+
Steep recognizes some special methods for type narrowing, including `#is_a?`, `#===`, `#nil?`, ... These methods are defined with normal RBS syntax, but the method types in shapes are transformed to types using logic types.
|
46
|
+
|
47
|
+
The shape calculation inserts the specialized methods with these special methods.
|
48
|
+
|
49
|
+
## `self` types
|
50
|
+
|
51
|
+
There are two cases of `self` types to consider during shape calculation.
|
52
|
+
|
53
|
+
1. `self` types included in the shape of a type
|
54
|
+
2. `self` types included in given types
|
55
|
+
|
56
|
+
### 1. `self` types included in the shape of a type
|
57
|
+
|
58
|
+
`self` types may be included in a class or interface definition.
|
59
|
+
|
60
|
+
```rbs
|
61
|
+
interface _Foo
|
62
|
+
def itself: () -> self
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
The `self` types included in the shape of `_Foo` type should be resolved to `_Foo` type.
|
67
|
+
|
68
|
+
```
|
69
|
+
Shape (_Foo) {
|
70
|
+
itself: () -> _Foo
|
71
|
+
}
|
72
|
+
```
|
73
|
+
|
74
|
+
### 2. `self` types included in given types
|
75
|
+
|
76
|
+
Unlike `self` types included in definitions, `self` types in given types should be preserved.
|
77
|
+
|
78
|
+
```rbs
|
79
|
+
interface _Foo[A]
|
80
|
+
def get: () -> A
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
The shape of `_Foo[self]` has `self` type as its type argument, and we want the `self` type preserved after the shape calculation.
|
85
|
+
|
86
|
+
```
|
87
|
+
Shape (_Foo[self]) {
|
88
|
+
get: () -> self
|
89
|
+
}
|
90
|
+
```
|
91
|
+
|
92
|
+
We often use `self` types as the return type of a method.
|
93
|
+
|
94
|
+
```rbs
|
95
|
+
class Foo
|
96
|
+
def foo: () -> self
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
So, the implementation of `foo` might use `self` node to return `self` type.
|
101
|
+
|
102
|
+
```rb
|
103
|
+
class Foo
|
104
|
+
def foo
|
105
|
+
# @type var foo: _Foo[self]
|
106
|
+
foo = ...
|
107
|
+
foo.get
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
We want the type of `foo.get` to be `self`, not `Foo`, to avoid a type error being detected.
|
113
|
+
|
114
|
+
## Shape of `self` types
|
115
|
+
|
116
|
+
We also want `self` type if `self` is the type of the shape.
|
117
|
+
|
118
|
+
```rb
|
119
|
+
class Foo
|
120
|
+
def foo
|
121
|
+
self.itself
|
122
|
+
end
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
This is a straightforward case, because the type of `self` is `self` itself. Calculate the shape of it, but keep the `self` types in the shape.
|
127
|
+
|
128
|
+
```
|
129
|
+
Shape (self) {
|
130
|
+
itself: () -> self
|
131
|
+
}
|
132
|
+
```
|
133
|
+
|
134
|
+
If `self` is a union type, or something built with a type constructor, the shape calculation gets complicated.
|
135
|
+
|
136
|
+
```rbs
|
137
|
+
class Foo
|
138
|
+
def foo: () -> Integer
|
139
|
+
end
|
140
|
+
|
141
|
+
class Bar
|
142
|
+
def foo: () -> self
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
What is the expected shape of `self` where the type of `self` is `Foo | Bar`?
|
147
|
+
|
148
|
+
The shape of a union type is straightforward. It calculates the shape of each type, and then it calculates a union of the shape.
|
149
|
+
|
150
|
+
We do the same for the case with `self` types, but it results in slightly incorrect shapes.
|
151
|
+
|
152
|
+
```
|
153
|
+
Shape (Foo) {
|
154
|
+
foo: () -> Integer
|
155
|
+
}
|
156
|
+
|
157
|
+
Shape (Bar) {
|
158
|
+
foo: () -> self # self is preserved, because the shape of `self` is being calculated
|
159
|
+
}
|
160
|
+
|
161
|
+
Shape (Foo | Bar) {
|
162
|
+
foo: () -> (Integer | self)
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
So, the resulting type of `self.foo` where the type of `self` is `Foo | Bar`, would be `Integer | Foo | Bar`. But, actually, it won't be `Foo` because the `self` comes from `Bar`.
|
167
|
+
|
168
|
+
This is an incorrect result, but Steep is doing this right now.
|
169
|
+
|
170
|
+
## `class` and `instance` types
|
171
|
+
|
172
|
+
The shape calculation provides limited support for `class` and `instance` types.
|
173
|
+
|
174
|
+
1. `class`/`instance` types from the definition are resolved
|
175
|
+
2. `class`/`instance` types in generics type arguments of interfaces/instances are preserved
|
176
|
+
3. Shape of `class`/`instance` types are resolved to configuration's `class_type` and `instance_type`, and the translated types are used to calculate the shape
|
177
|
+
|
178
|
+
It's different from `self` types except case #2. The relationship between `self`/`class`/`instance` is not trivial in Ruby. All of them might be resolved to any type, which means calculating one from another of them is simply impossible.
|
179
|
+
|
180
|
+
## Public methods, private methods
|
181
|
+
|
182
|
+
`Shape` objects have a flag of if the shape is for *public* method calls or *private* method calls. Private method call is a form of `foo()` or `self.foo()` -- when the receiver is omitted or `self`. Public method calls are anything else.
|
183
|
+
|
184
|
+
The shape calculation starts with *private methods*, and the `Shape#public_shape` method returns another shape that only has *public* methods.
|
185
|
+
|
186
|
+
> Note that the private shape calculation is required even on public method calls. This means a possible chance of future optimizations.
|
187
|
+
|
188
|
+
## Lazy method type calculation
|
189
|
+
|
190
|
+
We rarely need all of the methods available for an object. If we want to type check a method call, we only need the method type of that method. All other methods can be just ignored.
|
191
|
+
|
192
|
+
*Lazy method type calculation* is introduced for that case. Instead of calculating the types of all of the methods, it registers a block that computes the method type.
|
193
|
+
|
194
|
+
It is implemented in `Steep::Interface::Shape::Entry` and used to make the shape calculation of a union type faster.
|
@@ -12,30 +12,13 @@ Run rbs-collection-init to start setup.
|
|
12
12
|
$ rbs collection init
|
13
13
|
```
|
14
14
|
|
15
|
-
You have to edit
|
16
|
-
|
17
|
-
```
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
revision: main
|
23
|
-
repo_dir: gems
|
24
|
-
|
25
|
-
# A directory to install the downloaded RBSs
|
26
|
-
path: .gem_rbs_collection
|
27
|
-
|
28
|
-
gems:
|
29
|
-
# Skip loading rbs gem's RBS.
|
30
|
-
# It's unnecessary if you don't use rbs as a library.
|
31
|
-
- name: rbs
|
32
|
-
ignore: true
|
33
|
-
- name: steep
|
34
|
-
ignore: true
|
35
|
-
- name: rbs_rails # Add these lines if you use rbs_rails
|
36
|
-
ignore: true
|
37
|
-
- name: rbs_protobuf # Add these lines if you use rbs_protobuf
|
38
|
-
ignore: true
|
15
|
+
You have to edit your `Gemfile`. Specify `require: false` for gems for which you do not want type definitions.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'rbs', require: false
|
19
|
+
gem 'steep, require: false
|
20
|
+
gem 'rbs_rails', require: false
|
21
|
+
gem 'rbs_protobuf', require: false
|
39
22
|
```
|
40
23
|
|
41
24
|
Once you save the file, run the install command.
|
@@ -16,7 +16,7 @@ and install the gems.
|
|
16
16
|
$ bundle install
|
17
17
|
```
|
18
18
|
|
19
|
-
|
19
|
+
Alternatively, you can install it with the gem command.
|
20
20
|
|
21
21
|
```
|
22
22
|
$ gem install steep
|
@@ -26,14 +26,14 @@ Execute the following command to confirm if the command is successfully installe
|
|
26
26
|
|
27
27
|
```
|
28
28
|
$ steep version
|
29
|
-
$ bundle exec steep version #
|
29
|
+
$ bundle exec steep version # If you install with bundler
|
30
30
|
```
|
31
31
|
|
32
|
-
We omit the `bundle exec` prefix from the following commands. Run commands with the prefix if you
|
32
|
+
We omit the `bundle exec` prefix from the following commands. Run commands with the prefix if you installed Steep with Bundler.
|
33
33
|
|
34
34
|
## Type checking your first Ruby script
|
35
35
|
|
36
|
-
Run steep init command to generate the configuration file, Steepfile
|
36
|
+
Run the `steep init` command to generate the configuration file, `Steepfile`.
|
37
37
|
|
38
38
|
```
|
39
39
|
$ steep init
|
@@ -54,7 +54,7 @@ Type the following Ruby code in your editor, and save it as `lib/hello.rb`.
|
|
54
54
|
currencies = { US: "$", JP: "¥", UK: "£" }
|
55
55
|
country = %w(US JP UK).sample()
|
56
56
|
|
57
|
-
puts "Hello! The price is #{currencies[country
|
57
|
+
puts "Hello! The price is #{currencies[country]}100. 💸"
|
58
58
|
```
|
59
59
|
|
60
60
|
And type check it with Steep.
|
@@ -84,13 +84,13 @@ lib/hello.rb:4:39: [error] Cannot pass a value of type `(::String | nil)` as an
|
|
84
84
|
Detected 1 problem from 1 file
|
85
85
|
```
|
86
86
|
|
87
|
-
The error says that the type of the country variable causes a type error. It is expected to be a
|
87
|
+
The error says that the type of the country variable causes a type error. It is expected to be a symbol, but string or `nil` will be given.
|
88
88
|
|
89
89
|
Let's see how we can fix the error.
|
90
90
|
|
91
91
|
## Fixing the type error
|
92
92
|
|
93
|
-
The first step is converting the string value to a symbol. We can add to_sym call.
|
93
|
+
The first step is converting the string value to a symbol. We can add a `#to_sym` call.
|
94
94
|
|
95
95
|
```rb
|
96
96
|
currencies = { US: "$", JP: "¥", UK: "£" }
|
@@ -128,7 +128,7 @@ Instead, we can simply tell the type checker that the value of the country canno
|
|
128
128
|
|
129
129
|
The underlying type system supports flow-sensitive typing similar to TypeScript and Rust. It detects conditional expressions testing the value of a variable and propagates the knowledge that the value cannot be `nil`.
|
130
130
|
|
131
|
-
We can fix the type error with an or construct.
|
131
|
+
We can fix the type error with an `or` construct.
|
132
132
|
|
133
133
|
```rb
|
134
134
|
currencies = { US: "$", JP: "¥", UK: "£" }
|
@@ -137,7 +137,7 @@ country = %w(US JP UK).sample() or raise
|
|
137
137
|
puts "Hello! The price is #{currencies[country.to_sym]}100. 💸"
|
138
138
|
```
|
139
139
|
|
140
|
-
The change
|
140
|
+
The change lets the type checking succeed.
|
141
141
|
|
142
142
|
```
|
143
143
|
$ steep check
|
@@ -145,7 +145,7 @@ $ steep check
|
|
145
145
|
|
146
146
|
.........................................................
|
147
147
|
|
148
|
-
No type error detected.
|
148
|
+
No type error detected. 🫖
|
149
149
|
```
|
150
150
|
|
151
151
|
The `raise` method is called when `sample()` returns `nil`. Steep can reason the possible control flow based on the semantics of or in Ruby:
|
@@ -161,4 +161,3 @@ There are two possibilities of the type of the result of the `sample()` call, `n
|
|
161
161
|
## Next steps
|
162
162
|
|
163
163
|
This is a really quick introduction to using Steep. You may have noticed that I haven't explained anything about defining new classes or modules. See the RBS guide for more examples!
|
164
|
-
|