Skip to content

Fix NoMethodError when RBS file contains class/module alias decl#443

Closed
rhiroe wants to merge 1 commit intoruby:masterfrom
rhiroe:fix-rbs-class-module-alias-crash
Closed

Fix NoMethodError when RBS file contains class/module alias decl#443
rhiroe wants to merge 1 commit intoruby:masterfrom
rhiroe:fix-rbs-class-module-alias-crash

Conversation

@rhiroe
Copy link
Copy Markdown
Contributor

@rhiroe rhiroe commented Apr 27, 2026

Summary

Fix NoMethodError: undefined method 'define' for nil raised in Service#update_rbs_file whenever the workspace contains an RBS file with a class alias or module alias declaration (e.g. module YAML = Psych, class HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess).

Background

AST.create_rbs_decl has an intentionally empty when RBS::AST::Declarations::AliasDecl branch (class/module aliases are not yet implemented and are silently skipped).
However the empty when body returns nil, and the calling site AST.parse_rbs calls raw_decls.map { ... } without .compact, so the nil ends up in the resulting array and later crashes at decls.each {|decl| decl.define(@genv) }.

The two other callers of create_rbs_decl / create_rbs_member already use .compact after the map (see Genv#load_core_rbs in core/env.rb and SigModuleBaseNode#initialize in core/ast/sig_decl.rb). This PR aligns parse_rbs with the same pattern.

Reproduction

Put a single line in sig/foo.rbs:

module YAML = Psych

Start the LSP server: it crashes during workspace initialization with

NoMethodError: undefined method 'define' for nil
  decls.each {|decl| decl.define(@genv) }

Fix

Add .compact to the map in AST.parse_rbs. Class/module aliases remain unimplemented (skipped) — proper alias resolution is out of scope for this PR.

Test plan

  • Added scenario/rbs/class-module-alias.rb regression test
  • bundle exec rake test passes (415 tests, 0 failures)
  • Verified locally: real-world RBS with module YAML = Psych no longer crashes the LSP server

`AST.create_rbs_decl` has an empty `when RBS::AST::Declarations::AliasDecl`
branch that returns nil, but `AST.parse_rbs` did not `.compact` the result,
so the nil reached `decls.each {|decl| decl.define(@GenV) }` and crashed
the LSP server. The two other callers of `create_rbs_decl` /
`create_rbs_member` already use `.compact`; this aligns `parse_rbs` with
the same pattern.
@rhiroe rhiroe marked this pull request as ready for review April 27, 2026 06:33
@mame
Copy link
Copy Markdown
Member

mame commented Apr 28, 2026

@rhiroe Thanks! I think the real issue is that AST.create_rbs_decl returns nil. Once #444 is merged, it won't return nil anymore, so this change might no longer be needed. What do you think?

@rhiroe
Copy link
Copy Markdown
Contributor Author

rhiroe commented Apr 28, 2026

@mame Yes, you're right — I think it will become unnecessary.
The reason I opened this PR was that I wanted to at least get rid of the error even in case #444 doesn't get merged smoothly.

I'll leave it up to you whether to merge or close this PR, but since .compact is already used at:

decls = raw_decls.map do |raw_decl|
AST.create_rbs_decl(raw_decl, lenv)
end.compact

I think it would also be fine to either remove that one as well for consistency, or merge this PR to align with the existing similar code.

@mame
Copy link
Copy Markdown
Member

mame commented Apr 29, 2026

I have merged #444, so closing this. Thanks!

.compact is already used at:

That's sloppy ;-P

@mame mame closed this Apr 29, 2026
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