-
Notifications
You must be signed in to change notification settings - Fork 91
Release Note 1.5
Some of the highlights in Steep 1.5 are:
- Method call editor assistant improvements (#850, #851, #863, #865)
- Better flow-sensitive typing analysis (#783)
- Completion in RBS inside Ruby comments (#818)
- Go to type definition feature (#784)
- Ruby code diagnostics template update (#871)
Please read the upgrading guide for upgrading from earlier version of Steep.
You can install it with $ gem install steep
or using Bundler.
gem 'steep', '~> 1.5.0', require: false
See the CHANGELOG for the details.
Steep 1.5 provides two major improvements on editor assistant on method calls -- keyword argument completion and SignatureHelp parameter highlighting.
These two improvements helps the developers input method calls without disruption by displaying precise information in the pop up and providing completion.
The implementation is mainly done by tk0miya. 🙏
One of the major type checker core improvements in this release is in flow-sensitive typing.
Unreachable branch detection: Steep now shows diagnostics when unreachable branch is detected.
x = 123 # x is Integer
if x
puts "It's #{x}"
else
puts "It's falsy value" # The *else* branch is unreachable, because x cannot be `nil` nor `false`
end
This is useful but sometimes annoying because of the type definition of Array#[]
and Hash#[]
. Their return type is non-optional while it actually returns nil
. Our recommendation is make the diagnostic less verbose -- :information
or :hint
. But if you want to continue fixing the errors, you can explicitly add type assertion.
x = [1,2,3][0] #: Integer? # <<= Add type assertion to make it *optional*
if x
puts "x is #{x}"
else
puts "x is falsy"
end
Unreachable branch detection in case-when: Another possible constructs that may cause unreachable branch is case-when. Steep detects UnreachableValueBranch
diagnostic, not UnreachableBranch
here. The UnreachableValueBranch
is reported if
- The branch is unreachable, and
- The type of the body of the branch is not
bot
This is to support the following defensive coding patterns.
# Assume value is a variable with type of `Integer | String`
case value
when Integer
puts "value is Integer"
when String
puts "value is String"
else
raise "Unexpected value: #{value}"
end
Here the else
clause is technically unreachable, but we have it to make the code defensive. The key is the body of else
branch is raising an exception, and its type is bot
.
Safe navigation operator call adds an assumption that the receiver is non-nil:
if foo&.bar?
foo.do_something # foo is non-nil here
end
%a{pure}
calls with receiver of self
is pure too:
if self.foo
self.foo # foo is non-nil here
end
Type name completion works inside inline type annotations.
You have to trigger the completion (Ctrl-Space
in VSCode) explicitly to show the completion list.
Go to Type Definition allows jumping to the definition of the type of the node.
It's different from Go to Definition (jumping to RBS method definition from method calls) or Go to Implementation (jumping to method implementation). It may be less frequently used compared to them, but also important to inspect the type of a node.
Steep provides five Ruby code diagnostics templates.
-
default
template checks if your code is compatible with RBS type definitions, including use-sites -
lenient
template checks if your code defines classes/modules/methods compatible with respect to your RBS definitions (only definition-site) -
strict
template checks more detail of your Ruby code, helping to make your code (almost) type-safe -
silent
template ignores all diagnostics, use this for the case you just want code navigation features -
all_error
template makes all diagnostics error
Our recommendation is using strict
template, but if you want less errors reported try default
or lenient
template.
Diagnostics templates are updated. Using the same Steepfile
would produce different results than earlier versions of Steep.
Feel free to ignore diagnostics if you feel they doesn't help.
D = Steep::Diagnostic
target :app do
# Add the diagnostic configuration
# Based on `default` config, with your customization
configure_code_diagnostics(D::Ruby.default) do |config|
config[D::Ruby::NoMethod] = nil # `nil` to ignore the diagnostic
config[Ruby::UnreachableBranch] = :hint # Or you can specify `:error`, `:warning`, `:information`, or `:hint`
end
end
If you are not sure, use strict
template and see the results to find the diagnostics you don't want.
- 🆕
Ruby::UnreachableValueBranch
is introduced, explained above - 🆕
Ruby::UnreachableBranch
is introduced, explained above - 🆕
Ruby::RBSError
is introduced which reports errors on RBS in inline type annotations - 🔪
Ruby::ElseOnExhaustiveCase
is deprecated and no longer reported