Skip to content

Release Note 1.5

Soutaro Matsumoto edited this page Jul 13, 2023 · 7 revisions

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.

Method call editor assistant improvements

Steep 1.5 provides two major improvements on editor assistant on method calls -- keyword argument completion and SignatureHelp parameter highlighting.

signature-help

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. 🙏

Better flow-sensitive typing analysis

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

  1. The branch is unreachable, and
  2. 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

Completion in RBS inside Ruby comments

Type name completion works inside inline type annotations.

completion-rbs

You have to trigger the completion (Ctrl-Space in VSCode) explicitly to show the completion list.

Go to Type Definition feature

Go to Type Definition allows jumping to the definition of the type of the node.

type-definition

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.

Ruby code diagnostics template update

Steep provides five Ruby code diagnostics templates.

  1. default template checks if your code is compatible with RBS type definitions, including use-sites
  2. lenient template checks if your code defines classes/modules/methods compatible with respect to your RBS definitions (only definition-site)
  3. strict template checks more detail of your Ruby code, helping to make your code (almost) type-safe
  4. silent template ignores all diagnostics, use this for the case you just want code navigation features
  5. 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.

Upgrading guide

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 diagnostics changes

  • 🆕 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