Skip to content

Release Note 1.6

Soutaro Matsumoto edited this page Nov 9, 2023 · 4 revisions

Some of the highlights in Steep 1.6 are:

  • Improved text synchronization with LSP (#934, #935, #936)
  • Better type error message instead of UnresolvedOverloading (#941, #950)
  • Make nil is not NilClass (#920)
  • Improved type name completion with module/class aliases (#923)

You can install it with $ gem install steep or using Bundler.

gem 'steep', require: false, '~> 1.6.0'

See the CHANGELOG for the details.

Improved text synchronization with LSP

A few PRs are merged to improve text synchronization with Language Server.

Type checking now starts just after you change the code (#934). Steep started type checking after you save a file. This worked really well if you set up auto-save with short delay. But if you like saving files explicitly, it didn't start soon. The PR is to start type checking by changing the content of a file, with short delay.

Steep resets the file content when you open your file (#935). This lets you recover from a text synchronization failure, by closing and re-opening the file. Note that it doesn't start type checking automatically. You have to type something in the opened buffer.

Steep starts the LSP file watcher too (#936). When you change some .rb or .rbs file outside of the IDE, Steep receives a notification and it reads the file from the disk.

Better type error message instead of UnresolvedOverloading

#941 and #950 are to report better type error messages for the case UnresolvedOverloading was reported.

array = [1, 2, 3]
array.map! do |x|
  x.to_s                  # Type error! because `map!` doesn't allow the block to have another type
end

Steep <=1.5 reported an UnresolvedOverloading here, but Steep 1.6 reports BlockBodyTypeMismatch, which is more helpful to fix the problem.

It tries to reject overloads with type errors caused by arity mismatch -- the number of arguments is incorrect, and unexpected/missing block. If only one overload is left without arity mismatch, the type error reported to the overload is used.

In the example above, the #map! overload without block is removed because it reports an arity error -- RequiredBlockMissing. Then the BlockBodyTypeMismatch is reported.

Make nil is not NilClass

nil is no longer a subtype of NilClass (#920).

nil and NilClass were interchangeable in Steep <=1.5. But it potentially caused a type system problem that nil is a subclass of Object.

nil <: NilClass
  => nil <: Object because NilClass <: Object

An unintended consequence is Object? <: Object.

nil <: NilClass
  nil <: Object
    Object | nil <: Object
      Object? <: Object 

We don't want this because we want to make T? a different type from T for any T != top .

Note that NilClass <: nil still holds.

Diagnostics updates

Severity of BlockBodyTypeMismatch and BlockTypeMismatch in default and lenient templates is changed (#950). This is to prevent type errors reported an method call disappears by reporting fewer UnresolvedOverloading errors.