Skip to content

Fully qualify extend T::Generic & T::Helpers - #1001

Merged
dejmedus merged 1 commit into
mainfrom
jb-qualify-extend-t
Aug 13, 2026
Merged

Fully qualify extend T::Generic & T::Helpers#1001
dejmedus merged 1 commit into
mainfrom
jb-qualify-extend-t

Conversation

@dejmedus

@dejmedus dejmedus commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

To ensure T::Generic and T::Helpers don't conflict with user defined T constants, we can fully qualify inserted T::Generic/Helpers to ::T::

@dejmedus
dejmedus force-pushed the jb-qualify-extend-t branch 2 times, most recently from e02d892 to 90f5578 Compare August 6, 2026 23:00
unless already_extends?(node, /^(::)?T::Helpers$/)
extend_with("T::Helpers", into: node, at: insert_pos)
end
find_and_remove_existing_extend(node, /^(::)?T::Helpers$/)

@amomchilov amomchilov Aug 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure if we should try to fix a pre-existing extend T::Helpers like this.

It's a nice feature in theory, but narrow. There are many other explicit uses of T that would be problematic (T.untyped, T::Boolean, T.any, ...), which we couldn't patch up as easily/reliably. I'm inclined err of inaction, and require people fix their own explicit usages of T.

I suppose the distinction is: who wrote the T?

If our rewriter wrote it, we should be good stewards and ::T it. If devs wrote it explicitly in their own source, they should choose ::T if they want it (or rename their generic arg to not be called T).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@Morriar wdyt?

@dejmedus dejmedus Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Makes sense! I can drop those commits and open up something separately if we decide we want the behaviour later on. In that case I think it would make sense to remove already_extends? (rather than fixing) and just allow, potentially, a duplicate extends

RBS + pre-existing extends
# bin/console 
source = <<~RUBY
  # typed: true

  # @final
  #: [T]
  class Box
    extend T::Helpers
  end
RUBY

puts Spoom::Sorbet::Translate.rbs_comments_to_sorbet_sigs(
  source,
  file: "example.rb",
)
# typed: true

class Box
  extend ::T::Helpers # spoom inserted (still needed, otherwise we `extend` after `final!` unless we insert below)

  final!

  extend ::T::Generic

  T = type_member

  extend T::Helpers # source 
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In a similar vein, I think that's too narrow of a problem-solve to be worth it. It would make their extend T::Helpers, but other code like T.nilable still fail.

I think it's a simpler (more predictable) mental model for the developer if #: [T] always caused unqualified accesses to fail, consistently

@dejmedus dejmedus Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed:) I removed already_extends? so it will continue to behave as it has been (inserting without checking for pre-existing) and a [T] + existing T::Helpers/Generic will error as expected

@dejmedus
dejmedus force-pushed the jb-qualify-extend-t branch from 90f5578 to a7791d4 Compare August 10, 2026 18:16
@dejmedus
dejmedus marked this pull request as ready for review August 10, 2026 18:31
@dejmedus
dejmedus requested a review from a team as a code owner August 10, 2026 18:31
unless already_extends?(node, /^(::)?T::Helpers$/)
extend_with("T::Helpers", into: node, at: insert_pos)
end
extend_with("::T::Helpers", into: node, at: insert_pos)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's add a test doing this:

# @final
class Box
  extend T::Helpers
end

Do we add the extend anyway?

class Box
  extend T::Helpers
  extend ::T::Helpers
  final!
end

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes:) Since already_extends? wasn't finding the node we've been inserting a duplicate even if there was a pre-existing. If we wanted already_extends? fixed instead of removed we'd need some logic to insert in the correct place (after the extends). Your example ends up as:

# typed: true

class Box
  extend ::T::Helpers # spoom inserted 

  final!

  extend T::Helpers # pre-existing
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's add this as a test to show the behavior is expected

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added here:)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I moved the already_extends? removal out of this PR to #1014 so it can be attached to its own issue, but I've left the test here as behaviour is the same

@dejmedus
dejmedus force-pushed the jb-qualify-extend-t branch from a7791d4 to 41be386 Compare August 11, 2026 16:28
Previously, a TypeError could be raised when we tried
to insert an `extend T::Generic` or `extend T::Helpers`
into a class that had a generic type member called `T`

This commit fully qualifies inserted extends to
`::T::Generic` and `::T::Helpers` to prevent this
@dejmedus
dejmedus force-pushed the jb-qualify-extend-t branch from 41be386 to 0bee885 Compare August 11, 2026 21:10
@dejmedus
dejmedus merged commit b01ca88 into main Aug 13, 2026
11 checks passed
@dejmedus
dejmedus deleted the jb-qualify-extend-t branch August 13, 2026 16:18
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.

Generic types called T can lead to TypeError

3 participants