Skip to content

Autocorrect RBS assertions on receivers - #411

Open
Morriar wants to merge 3 commits into
mainfrom
rbs-receiver-assertions
Open

Autocorrect RBS assertions on receivers#411
Morriar wants to merge 3 commits into
mainfrom
rbs-receiver-assertions

Conversation

@Morriar

@Morriar Morriar commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Extend the shared RBS assertion autocorrector to support Sorbet assertions used as method receivers.

This applies to:

  • Sorbet/ForbidTCast
  • Sorbet/ForbidTLet
  • Sorbet/ForbidTUnsafe

This PR is stacked on #410, which adds support for assertions used as method arguments.

Examples

A receiver chain beginning a statement:

T.unsafe(foo).bar

is corrected to:

foo #: as untyped
  .bar

The same applies to longer chains and safe navigation:

T.cast(foo, String).bar.baz
T.let(foo, String)&.bar

become:

foo #: as String
  .bar.baz

foo #: String
  &.bar

Receiver chains used as the complete right-hand side of an assignment are also supported:

x = T.unsafe(foo).bar

becomes:

x = foo #: as untyped
  .bar

Semantics

The generated RBS comments preserve the original Sorbet operation:

  • T.unsafe(foo)foo #: as untyped
  • T.cast(foo, Type)foo #: as Type
  • T.let(foo, Type)foo #: Type

In particular, T.unsafe uses #: as untyped, not #: untyped. The latter represents T.let(foo, T.untyped) and would change semantics.

The generated forms were validated against Sorbet’s RBS rewrite phase.

Guardrails

The autocorrect declines receiver chains when rewriting only the receiver would cause the trailing RBS comment to consume surrounding syntax.

Unsupported embedded contexts include:

wrapper(T.unsafe(foo).bar)
return T.unsafe(foo).bar
other + T.unsafe(foo).bar

These require restructuring the enclosing expression, generally by adding parentheses and expanding it across multiple lines.

The correction also declines:

  • Receiver chains inside single-line blocks
  • Multiline assertions or receiver chains
  • Receiver chains containing comments
  • Receiver chains containing multiple matching assertions
  • Receiver chains with an existing RBS annotation

T.bind and T.absurd are intentionally excluded. Their RBS replacements are statement-oriented and do not compose naturally as receiver expressions.

@Morriar
Morriar requested a review from a team as a code owner August 13, 2026 13:43
RUBY
end

def test_autocorrects_t_unsafe_used_as_a_receiver

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an example where the T unsafe happens in the middle of a call chain? For example:

T.unsafe(foo.bar).baz

# Needs to become
foo.bar #: as unsafe
  .baz

@Morriar
Morriar force-pushed the rbs-nested-assertions branch from dc12370 to 255b396 Compare August 20, 2026 15:02
Base automatically changed from rbs-nested-assertions to main August 25, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants