-
Notifications
You must be signed in to change notification settings - Fork 135
next
stops in the wrong place when blocks are called
#763
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
Comments
Here's a protocol test that should pass when the issue is fixed: # frozen_string_literal: true
require_relative '../support/protocol_test_case'
module DEBUGGER__
class NextDynamicMethodTest < ProtocolTestCase
PROGRAM = <<~RUBY
1| class Bar
2| define_method("dynamic") do
3| "dynamic"
4| end
5|
6| def regular
7| "regular"
8| end
9| end
10|
11| def foo(a, b, c); end
12|
13| bar = Bar.new
14| foo(
15| bar.regular,
16| bar.dynamic,
17| bar.regular
18| )
19| bar
RUBY
def test_next_goes_to_the_next_statement
run_protocol_scenario PROGRAM do
req_next
assert_line_num 2
assert_locals_result(
[
{ name: "%self", value: "Bar", type: "Class" },
]
)
req_next
assert_line_num 6
assert_locals_result(
[
{ name: "%self", value: "Bar", type: "Class" },
]
)
req_next
assert_line_num 11
assert_locals_result(
[
{ name: "%self", value: "main", type: "Object" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_next
assert_line_num 13
assert_locals_result(
[
{ name: "%self", value: "main", type: "Object" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_next
assert_line_num 14
assert_locals_result(
[
{ name: "%self", value: "main", type: "Object" },
{ name: "bar", value: /#<Bar/, type: "Bar" }
]
)
req_next
assert_line_num 19
assert_locals_result(
[
{ name: "%self", value: "main", type: "Object" },
{ name: "bar", value: /#<Bar/, type: "Bar" }
]
)
req_terminate_debuggee
end
end
end
end |
next
stops in the wrong place when dynamically-defined methods are callednext
stops in the wrong place when blocks are called
cc @WillHalto. Just a heads up that #743 doesn't seem to make this worse, but given that you are already there and have some context, you might find it interesting. |
A small tip: you can write the reproduction steps down like: debugger(do: "b 6 ;; c ;; n ;; n ;; n")
def with_block
yield
end
with_block do
1
end
puts("`next` should stop here") In this case, we only need to run $ rdbg -n target.rb And the reproduction steps can be executed automatically. If you don't want to modify the script directly, you can achieve it with def with_block
yield
end
with_block do
1
end
puts("`next` should stop here") $ rdbg -e "b 5 ;; c ;; n ;; n ;; n" target.rb |
After some investigation, I think the simple and complicated examples have different causes. I can't really tell the cause of the simple case yet. But for the complicated example, I think it's caused by a bug in older Ruby versions. Example TracePoint.new(:b_return, :return) do |tp|
puts [tp.event, caller_locations(1, 1).first].to_s
end.enable
class Bar
define_method("dynamic") do
true
end # line 8
end
Bar.new.dynamic # line 11 If you execute this script with Ruby < 3.1, you'll get
And you can see that However, if you run it with Ruby 3.1, they do match
If you run the complicated case with Ruby 3.1, it actually works as expected:
So I think it's more like a bug in older Ruby versions, but we may workaround it in |
It solved on Ruby 3.1.0 and later. |
I don't know what your policy is in supporting Ruby < 3.1.0... but, as it is, with this issue and #760, the debugger has a really poor experience. Given that we still have 6 months until the end of life of Ruby 2.6 (and no date for 2.7), I'd argue for at least keeping this open, and try to fix it. |
Last time I tested, the simple case's issue also happened with ❯ ruby -v
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-darwin21]
❯ be exe/rdbg target.rb
[1, 8] in target.rb
=> 1| def with_block
2| yield
3| end
4|
5| with_block do
6| 1
7| end
8| puts("`next` should stop here")
=>#0 <main> at target.rb:1
(rdbg) b 5 # break command
#0 BP - Line /Users/st0012/projects/debug/target.rb:5 (line)
(rdbg) c # continue command
[1, 8] in target.rb
1| def with_block
2| yield
3| end
4|
=> 5| with_block do
6| 1
7| end
8| puts("`next` should stop here")
=>#0 <main> at target.rb:5
Stop by #0 BP - Line /Users/st0012/projects/debug/target.rb:5 (line)
(rdbg) n # next command
[1, 8] in target.rb
1| def with_block
2| yield
3| end
4|
5| with_block do
=> 6| 1
7| end
8| puts("`next` should stop here")
=>#0 block in <main> at target.rb:6
#1 Object#with_block at target.rb:2
# and 1 frames (use `bt' command for all frames)
(rdbg) n # next command
[2, 8] in target.rb
2| yield
3| end
4|
5| with_block do
6| 1
=> 7| end
8| puts("`next` should stop here")
=>#0 block in <main> at target.rb:7 #=> 1
#1 Object#with_block at target.rb:2
# and 1 frames (use `bt' command for all frames)
<===== Ideally this step shouldn't happen =====>
(rdbg) n # next command
[1, 8] in target.rb
1| def with_block
2| yield
=> 3| end
4|
5| with_block do
6| 1
7| end
8| puts("`next` should stop here")
=>#0 Object#with_block at target.rb:3 #=> 1
#1 <main> at target.rb:5
(rdbg) n # next command
[3, 8] in target.rb
3| end
4|
5| with_block do
6| 1
7| end
=> 8| puts("`next` should stop here")
=>#0 <main> at target.rb:8
(rdbg) n # next command
`next` should stop here So based on that I think we should keep this issue opened until we're clear on both cases' causes. |
It's also worth mentioning that, for anyone using Sorbet, trying to step with sig {returns(T::Boolean)}
def does_it_work?
false
end
value = does_it_work?
puts("Does it work? #{value}") Trying to step over 6 requires two |
I think additional |
There are actually 2 problems (as identified by @st0012 above):
They are definitely a very bad experience when debugging anything but a trivial codebase |
I understand the issue. def iter
yield
end # (iter/end)
iter do
1
end # (*) Now stopping here
puts("`next` should stop here") # (putline)
Options:
Now, |
In the case above, 2 (at the line with What I would expect is 1 (thus this ticket), but I'd be OK (as in: "I don't like this much, but at least doesn't surprise me") with either stopping inside the |
When stopping at line |
ah, I see on the original issue:
You want to skip block call at all.
(3) seems valuable to reconsidered. But now I don't have correct way to fix... |
v1.7.0 may fix this issue. |
I can confirm that, at least in ruby 2.7, this is still not fixed. I've simplified the test enough to this: class NextDynamicMethodTest < ProtocolTestCase
PROGRAM = <<~RUBY
1| class Bar
2| define_method("dynamic") do
3| "dynamic"
4| end
5|
6| def regular
7| "regular"
8| end
9| end
10|
11| def foo(a, b, c); end
12|
13| bar = Bar.new
14| foo(
15| bar.regular,
16| bar.dynamic,
17| bar.regular
18| )
19| bar
RUBY
def test_next_goes_to_the_next_statement
run_protocol_scenario PROGRAM do
req_add_breakpoint 14
req_continue
assert_line_num 14
req_next
assert_line_num 19 # When `TracePoint` returns the wrong number for :return after :b_return, this is 16
req_terminate_debuggee
end
end
end |
Thank you I verified
|
Coming back to this after I'm using Ruby 3.1, and I can verify that the issue is solved |
Your environment
ruby -v
: 2.7.2p137rdbg -v
: 1.6.2To Reproduce
For a simple case:
next
For more complex cases:
foo
is)next
Expected behavior
The debugger should stop at line 8 in the simple example, and 17 in the complex one
Additional context
I included non-dynamically-defined methods, to show that
next
only behaves incorrectly for the dynamically-defined ones (as it doesn't stop at line 13 nor 15)The text was updated successfully, but these errors were encountered: