Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Right hand assignment inside case/when/end causes cannot get the first element of beginless range (RangeError) #1434

Open
DimaD opened this issue Mar 15, 2022 · 3 comments · Fixed by bradfeehan/yard#1

Comments

@DimaD
Copy link

DimaD commented Mar 15, 2022

Yards AST parser raises cannot get the first element of beginless range (RangeError) when using right-hand assignment and restructuring.

I have tried using restructuring in different contexts and only the use from the examples below inside of the case statement causes an error.

Steps to reproduce

Example 1 - causes an error

case 1
when 1
  [1] => [a]
end

Example 2 - causes an error

case 1
when 1
  {a: 1} => {a:}
end

Example 3 - no error
The error does not occur in every context, I was only able to trigger it inside the case/when statement.

def m
  [1] => [a]
end

Actual Output

% be yardoc --debug broken-yard.rb                                            
[debug]: Parsing ["broken-yard.rb"] with `ruby` parser
[debug]: Parsing broken-yard.rb
bundler: failed to load command: yardoc (/Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/bin/yardoc)
/Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:274:in `first': cannot get the first element of beginless range (RangeError)
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:274:in `line'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:624:in `block in insert_comments'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:212:in `traverse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:615:in `insert_comments'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:60:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:17:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:442:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:46:in `block in parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/logging.rb:82:in `capture'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:45:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:371:in `parse_in_order'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:114:in `block in parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/logging.rb:182:in `enter_level'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:113:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard.rb:20:in `parse'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/cli/yardoc.rb:259:in `block in run'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/serializers/yardoc_serializer.rb:56:in `lock_for_writing'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/registry_store.rb:202:in `lock_for_writing'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/registry.rb:210:in `lock_for_writing'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/cli/yardoc.rb:258:in `run'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/lib/yard/cli/command.rb:14:in `run'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/gems/yard-0.9.27/bin/yardoc:13:in `<top (required)>'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/bin/yardoc:23:in `load'
	from /Users/testuser/src/yard_examples/vendor/bundle/ruby/3.0.0/bin/yardoc:23:in `<top (required)>'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli/exec.rb:58:in `load'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli/exec.rb:58:in `kernel_load'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli/exec.rb:23:in `run'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli.rb:478:in `exec'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli.rb:31:in `dispatch'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/cli.rb:25:in `start'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/bundler-2.2.32/libexec/bundle:49:in `block in <top (required)>'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/3.0.0/bundler/friendly_errors.rb:103:in `with_friendly_errors'
	from /Users/testuser/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/bundler-2.2.32/libexec/bundle:37:in `<top (required)>'
	from /Users/testuser/.rbenv/versions/3.0.3/bin/bundle:23:in `load'
	from /Users/testuser/.rbenv/versions/3.0.3/bin/bundle:23:in `<main>'

Expected Output

I expect no errors and no docs produced from the example

Files:           0
Modules:         0 (    0 undocumented)
Classes:         0 (    0 undocumented)
Constants:       0 (    0 undocumented)
Attributes:      0 (    0 undocumented)
Methods:         0 (    0 undocumented)
 100.00% documented

Environment details:

  • OS: macOS 11.6.2 (20G314)
  • Ruby version (ruby -v): ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [arm64-darwin20]
  • YARD version (yard -v): yard 0.9.27

I have read the Contributing Guide.

@akimd
Copy link

akimd commented Apr 4, 2022

I have a similar failure, but with a different pattern (heavily stripped down)

    case [self, other]
    in [MetaType[id], *]
      if other in MetaType[id2]
      end
    end
/opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:274:in `first': cannot get the first element of beginless range (RangeError)
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:274:in `line'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:624:in `block in insert_comments'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:212:in `traverse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:615:in `insert_comments'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:60:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:17:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:442:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:46:in `block in parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/logging.rb:82:in `capture'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:45:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:371:in `parse_in_order'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:114:in `block in parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/logging.rb:182:in `enter_level'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/source_parser.rb:113:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard.rb:20:in `parse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/cli/yardoc.rb:259:in `block in run'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/serializers/yardoc_serializer.rb:56:in `lock_for_writing'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/registry_store.rb:202:in `lock_for_writing'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/registry.rb:210:in `lock_for_writing'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/cli/yardoc.rb:258:in `run'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/cli/command.rb:14:in `run'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/bin/yardoc:13:in `<top (required)>'
	from /opt/local/bin/yardoc:25:in `load'
	from /opt/local/bin/yardoc:25:in `<main>'

@akimd
Copy link

akimd commented Apr 4, 2022

I believe the proper fix is in lib/yard/parser/ruby/ast_node.rb to replace:

        def line
          line_range && line_range.first
        end

by

        def line
          line_range && line_range.begin
        end

since begin always returns the "first" element, as nil if it does not exist (while first dies if begin is nil).

However in that case yardoc dies farther:

/opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:624:in `block in insert_comments': undefined method `-' for nil:NilClass (NoMethodError)

            ((node.line - 1).downto(node.line - 2).to_a + [node.line]).each do |line|
                        ^
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ast_node.rb:212:in `traverse'
	from /opt/local/lib/ruby3.1/gems/3.1.0/gems/yard-0.9.27/lib/yard/parser/ruby/ruby_parser.rb:615:in `insert_comments'

so it looks like after all it does not like line to return nil, contrary to what the && seems to imply. So I made it

        def line
          line_range && line_range.begin || 1
        end

and this time yardoc finishes properly.

@akimd
Copy link

akimd commented Apr 4, 2022

It turns out I also need to change reset_line_info in the same file:

            self.line_range = Range.new(f.line_range.begin || 1, l.line_range.last)
            self.source_range = Range.new(f.source_range.begin || 1, l.source_range.last)

instead of using .first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants