Bug #3011

caller for recursive function

Added by Marc-Andre Lafortune about 4 years ago. Updated almost 2 years ago.

[ruby-core:28963]
Status:Closed
Priority:Low
Assignee:Nobuyoshi Nakada
Category:core
Target version:Ruby 1.8.8
ruby -v:ruby 1.8.8dev (2010-03-25) [i386-darwin10.2.0]

Description

=begin
For some reason, Ruby 1.8 will skip multiple copies of the same method. In case of a recursive function call, the behavior is different from Ruby 1.9 and seems wrong.

Here's the rubyspec I just committed:

 it "returns one entry per call, even for recursive methods" do
   def recurse(n)
     return caller if n <= 0
     recurse(n-1)
   end
   (recurse(3).size - recurse(2).size).should == 1
 end

The following patch doesn't seem to yield any new failure with make test, make test-all, nor the caller specs:

diff --git a/eval.c b/eval.c
index 3407548..65fb970 100644
--- a/eval.c
+++ b/eval.c
@@ -6468,9 +6468,6 @@ backtrace(lev)
}
for (; frame && (n = frame->node); frame = frame->prev) {
if (frame->prev && frame->prev->lastfunc) {
- if (frame->prev->node == n) {
- if (frame->prev->last
func == frame->lastfunc) continue;
- }
snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
n->nd
file, ndline(n),
rb
id2name(frame->prev->last_func));

Nobu, can you recall what was the reason for these lines ( r10593 ) ?
=end

History

#1 Updated by Nobuyoshi Nakada about 4 years ago

=begin
Hi,

At Thu, 25 Mar 2010 10:38:57 +0900,
Marc-Andre Lafortune wrote in :

For some reason, Ruby 1.8 will skip multiple copies of the
same method. In case of a recursive function call, the
behavior is different from Ruby 1.9 and seems wrong.

According to the log and ML archive, it was origined from
r8590, and intended to veil implicitly called method names.
e.g.: to make the former to the latter.

$ ruby -e 'p [0].maxby'
-e:1:in max_by': no block given (LocalJumpError)
from -e:1:in
each'
from -e:1:in `max
by'
from -e:1

$ ruby -e 'p [0].maxby'
-e:1:in `max
by': no block given (LocalJumpError)
from -e:1

But something seems to have changed and it doesn't work
expectedly now.

The following patch doesn't seem to yield any new failure
with make test, make test-all, nor the caller specs:

Seems nice.

Another idea is to reduce same methods like following patch,
but it may cause other issues.

diff --git i/eval.c w/eval.c
index 3407548..159ed0e 100644
--- i/eval.c
+++ w/eval.c
@@ -6437,4 +6437,5 @@ backtrace(lev)
VALUE ary;
NODE *n;
+ int succ = 0;

  ary = rb_ary_new();

@@ -6467,15 +6468,22 @@ backtrace(lev)
}
}
- for (; frame && (n = frame->node); frame = frame->prev) {
+ for (frame && (n = frame->node); frame = frame->prev) {
+ const char *name = 0;
if (frame->prev && frame->prev->lastfunc) {
- if (frame->prev->node == n) {
- if (frame->prev->last
func == frame->lastfunc) continue;
+ if (frame->prev->node == n && frame->prev->last
func == frame->lastfunc) {
+ succ++;
+ continue;
}
- snprintf(buf, BUFSIZ, "%s:%d:in %s'",
- n->nd_file, nd_line(n),
- rb_id2name(frame->prev->last_func));
+ name = rb_id2name(frame->prev->last_func);
}
- else {
- snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n));
+ snprintf(buf, BUFSIZ, "%s:%d", n->nd_file, nd_line(n));
+ if (name) {
+ long len = strlen(buf);
+ snprintf(buf + len, BUFSIZ - len, ":in
%s'", name);
+ len += strlen(buf + len);
+ if (succ > 0) {
+ snprintf(buf + len, BUFSIZ - len, " (%d levels)", succ + 1);
+ succ = 0;
+ }
}
rb
arypush(ary, rbstr_new2(buf));

--
Nobu Nakada

=end

#2 Updated by Shyouhei Urabe over 3 years ago

  • Status changed from Open to Assigned

=begin

=end

#3 Updated by Marc-Andre Lafortune almost 2 years ago

  • Description updated (diff)
  • Status changed from Assigned to Closed

Also available in: Atom PDF