Shopify/packwerk

[Bug Report] Packwerk::NodeHelpers::TypeError when using module_parent in a class definition

Bernie opened this issue · 0 comments

Description
When using module_parent in a class definition, packwerk raises this error:

spec/my_spec.rb

Packwerk encountered an internal error.
For now, you can add this file to packwerk.yml exclude list.
Please file an issue and include this error message and stacktrace:

Packwerk::NodeHelpers::TypeError ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:58:in constant_name' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:53:in constant_name'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/const_node_inspector.rb:45:in constant_in_module_or_class_definition?' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/const_node_inspector.rb:24:in constant_name_from_node'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:83:in block in reference_from_node' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:82:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:82:in reference_from_node' ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_processor.rb:29:in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:22:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:79:in references_from_ast' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:50:in block in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cache.rb:78:in with_cache' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:46:in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/run_context.rb:78:in process_file' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/parse_run.rb:57:in block in process_file_proc'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:587:in call_with_index' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:557:in process_incoming_jobs'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:537:in block in worker' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:20:in block in fork'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:18:in fork' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:18:in fork'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:528:in worker' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:519:in block in create_workers'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in each_with_index'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in create_workers' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:457:in work_in_processes'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:294:in map' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:307:in flat_map'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/parse_run.rb:38:in find_offenses' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/commands/check_command.rb:27:in block in run'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/benchmark-0.2.1/lib/benchmark.rb:311:in realtime' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/formatters/progress_formatter.rb:29:in started_inspection'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/commands/check_command.rb:26:in run' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cli.rb:58:in execute_command'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cli.rb:41:in run' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/exe/packwerk:16:in <top (required)>'
bin/packwerk:31:in load' bin/packwerk:31:in

'"

To Reproduce

  1. Create a spec file like so:
RSpec.describe "this bug" do
  class self::MyTestClass
  end

  context "my nested context" do
    class self::MyTestClass < module_parent::MyTestClass
    end
  end
end
  1. Run packwerk check on the spec file
  2. Watch Packwerk explode

Expected Behaviour
Packwerk not to crash with an exception

Version Information

  • Packwerk: [3.2.0]
  • Ruby [3.0.6]

Additional Context
There is a workaround by simply omitting the module_parent prefix like so:

RSpec.describe "this bug" do
  class self::MyTestClass
  end

  context "my nested context" do
    class self::MyTestClass < self::MyTestClass
    end
  end
end

This appears to be equivalent in Ruby and does not crash packwerk. However, this less explicit syntax may be less understandable for some people.