Skip to content

Conversation

@sinsoku
Copy link
Contributor

@sinsoku sinsoku commented Nov 20, 2025

When a constant is assigned the result of Class.new (e.g.,
MyError = Class.new(StandardError)), TypeProf now correctly infers
the constant as a singleton type instead of a Class instance.

This fixes a NoMethodError when using such dynamically created
classes in rescue clauses with assignment (rescue MyError => e).

Changes:

  • Detect Class.new pattern in ConstantWriteNode#install0
  • Create singleton type for the constant when Class.new is detected
  • Support both Class.new and ::Class.new patterns

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

When a constant is assigned the result of Class.new (e.g.,
MyError = Class.new(StandardError)), TypeProf now correctly infers
the constant as a singleton type instead of a Class instance.

This fixes a NoMethodError when using such dynamically created
classes in rescue clauses with assignment (rescue MyError => e).

Changes:
- Detect Class.new pattern in ConstantWriteNode#install0
- Create singleton type for the constant when Class.new is detected
- Support both Class.new and ::Class.new patterns

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
mame added a commit to mame/typeprof that referenced this pull request Dec 3, 2025
Previously, TypeProf would crash when encountering `rescue X => e` if
`X` was a non-class constant (e.g., `X = 1`).

This commit fixes the issue by handling cases where the rescued object
is not a singleton type, preventing the unhandled exception during type
inference.

Fixes ruby#351

Co-Authored-By: Takumi Shotoku <sinsoku.listy@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@mame
Copy link
Member

mame commented Dec 3, 2025

Thank you. I believe this issue involves two distinct aspects:

  1. The crash that occurs when writing rescue X => e where X is a non-class constant.
  2. The desire to handle MyError = Class.new(StandardError) effectively as class MyError < StandardError.

The first point is definitely a bug. However, even with this PR applied, rescue X => e (where X = 1) still causes the same crash. I plan to fix this specific crash in #353.

The second point is a valuable improvement, and I understand this PR aims to implement it. However, it doesn't appear to be working as intended yet. Given the following code:

class Foo
end

Bar = Class.new(Foo)

def check
  Bar.new
end

I would expect the following inference result:

class Foo
end
class Bar < Foo
end
class Object
  def check: -> Bar
end

Unfortunately, the actual result is currently:

class Foo
end
Bar: Class
class Object
  def check: -> untyped
end

This is an interesting challenge, but it looks like it might require significant changes to the codebase, so I would like to postpone addressing it for a little while.

mame added a commit that referenced this pull request Dec 3, 2025
Previously, TypeProf would crash when encountering `rescue X => e` if
`X` was a non-class constant (e.g., `X = 1`).

This commit fixes the issue by handling cases where the rescued object
is not a singleton type, preventing the unhandled exception during type
inference.

Fixes #351

Co-Authored-By: Takumi Shotoku <sinsoku.listy@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@mame mame closed this in #353 Dec 3, 2025
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