Project

General

Profile

Actions

Bug #22302

open

Prism and parse.y disagree on the `:line` event for a bare `nil` method body

Bug #22302: Prism and parse.y disagree on the `:line` event for a bare `nil` method body

Added by Eregon (Benoit Daloze) about 3 hours ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM [x86_64-linux]
[ruby-core:126625]

Description

Summary

The Prism compiler and the parse.y compiler produce a different set of :line trace points (line events) for a bare nil literal that is the value-producing body of a method. Prism emits a line event on the nil's own line; parse.y does not.

def m
  nil
end
  • With --parser=prism, executing m (or setting a TracePoint(:line) / coverage / a debugger breakpoint) reports a line event on line 2.
  • With --parser=parse.y, there is no line event on line 2.

Reproduction

Compile-time line events

def line_events(iseq)
  events = iseq.trace_points.select { |_, event| event == :line }.map(&:first)
  iseq.each_child { |child| events.concat(line_events(child)) }
  events.sort
end

p line_events(RubyVM::InstructionSequence.compile("def m\n  nil\nend\n"))
$ ruby --parser=prism   repro.rb
[1, 2]
$ ruby --parser=parse.y repro.rb
[1]

Runtime :line events

seen = []
TracePoint.new(:line) { |tp| seen << tp.lineno if tp.path.end_with?("body.rb") }.enable do
  File.write("body.rb", "def m\n  nil\nend\nm\n")
  load "./body.rb"
end
p seen.sort
$ ruby --parser=prism   rt.rb
[1, 2, 4]
$ ruby --parser=parse.y rt.rb
[1, 4]

Under Prism a line event fires on line 2 (the nil) when m is called; under parse.y it does not.

Instruction sequences

The method body iseq differs only in the line attributed to the putnil, and whether it carries the line event ([Li]):

# --parser=parse.y
0000 putnil    (   1)[Ca]
0001 leave     (   3)[Re]

# --parser=prism
0000 putnil    (   2)[LiCa]
0001 leave     (   3)[Re]

parse.y attributes the method's implicit-nil putnil to the definition line (1) with only the RUBY_EVENT_CALL flag, so no line event is emitted for line 2.
Prism attributes the putnil to the nil's own line (2) and emits a line event there.

Scope of the difference

The difference is specific to a bare nil in method (def/defs) tail position. Other cases behave the same under both parsers:

  • Other literals in the same position emit a line event under both parsers (def m; true; end, def m; 1; end, def m; :a; end, def m; "s"; end).
  • A bare nil at the top level, or as the body of a block or lambda, emits a line event under both parsers.
  • The failing shape also occurs when the tail nil is reached through the branch of a conditional, e.g. a method whose body is if cond; nil; elsif ...; end.

The behavior is consistent across Ruby versions: parse.y has never emitted the line event for this case (checked back to 2.3), and Prism has emitted it since its compiler could be selected. This is a standing difference between the two compilers rather than a recent change; it only became visible by default when Prism became the default parser.

Note on the cause

This difference stems from void-expression elimination: parse.y treats the trailing nil as the method's implicit nil return and elides it (compiling a synthetic putnil with no line event), whereas Prism keeps it as an explicit value expression that carries a line event.
It is not ideal that whether a :line event is emitted depends on whether an expression is eliminated as void, but that coupling is already the established behavior in both compilers — an unused bare literal in non-tail statement position (e.g. 1 or :a followed by another statement) likewise loses its line event under both parsers — so this is not unique to the case here, only the one place the two happen to disagree.

Question

Which behavior is intended — should a bare nil in method tail position emit a :line event or not? Currently the two parsers disagree, which affects TracePoint(:line), line coverage, and debuggers depending on which parser compiled the code.

Environment

ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM [x86_64-linux]

Also reproduced on ruby 3.4.0 with --parser=prism / --parser=parse.y.

(found in https://github.com/ruby/prism/pull/4223)

No data to display

Actions

Also available in: PDF Atom