Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ jobs:

- name: test
timeout-minutes: 30
run: make test
run: make test test-tool
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no'
Expand Down
10 changes: 10 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ Note that each entry is kept to a minimum, see links for details.

Note: We're only listing outstanding class updates.

* Method

* `Method#source_location`, `Proc#source_location`, and
`UnboundMethod#source_location` now return extended location
information with 5 elements: `[path, start_line, start_column,
end_line, end_column]`. The previous 2-element format `[path,
line]` can still be obtained by calling `.take(2)` on the result.
[[Feature #6012]]

* Set

* A deprecated behavior, `Set#to_set`, `Range#to_set`, and
Expand Down Expand Up @@ -66,4 +75,5 @@ A lot of work has gone into making Ractors more stable, performant, and usable.

## JIT

[Feature #6012]: https://bugs.ruby-lang.org/issues/6012
[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
9 changes: 7 additions & 2 deletions bignum.c
Original file line number Diff line number Diff line change
Expand Up @@ -7070,7 +7070,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
zn = mn;
z = bignew(zn, 1);
bary_powm_gmp(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn, BDIGITS(m), mn);
if (nega_flg & BIGNUM_POSITIVE_P(z)) {
if (nega_flg && BIGNUM_POSITIVE_P(z) && !BIGZEROP(z)) {
z = rb_big_minus(z, m);
}
RB_GC_GUARD(x);
Expand Down Expand Up @@ -7098,7 +7098,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
x = rb_int_modulo(x, m);
}

if (nega_flg && rb_int_positive_p(tmp)) {
if (nega_flg && rb_int_positive_p(tmp) && !rb_int_zero_p(tmp)) {
tmp = rb_int_minus(tmp, m);
}
return tmp;
Expand Down Expand Up @@ -7210,6 +7210,11 @@ rb_int_powm(int const argc, VALUE * const argv, VALUE const num)
rb_raise(rb_eTypeError, "Integer#pow() 2nd argument not allowed unless all arguments are integers");
}

if (rb_int_zero_p(a) && !rb_int_zero_p(b)) {
/* shortcut; 0**x => 0 except for x == 0 */
return INT2FIX(0);
}

if (rb_int_negative_p(m)) {
m = rb_int_uminus(m);
nega_flg = 1;
Expand Down
2 changes: 1 addition & 1 deletion class.c
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool boxable)
static VALUE
class_alloc(enum ruby_value_type type, VALUE klass)
{
bool boxable = BOX_ROOT_P(rb_current_box());
bool boxable = rb_box_available() && BOX_ROOT_P(rb_current_box());
return class_alloc0(type, klass, boxable);
}

Expand Down
10 changes: 9 additions & 1 deletion gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -5329,15 +5329,23 @@ rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
{
rb_objspace_t *objspace = objspace_ptr;

return RVALUE_MARKED(objspace, obj);
bool marked = RVALUE_MARKED(objspace, obj);

if (marked) {
rgengc_check_relation(objspace, obj);
}

return marked;
}

static void
gc_update_weak_references(rb_objspace_t *objspace)
{
VALUE *obj_ptr;
rb_darray_foreach(objspace->weak_references, i, obj_ptr) {
gc_mark_set_parent(objspace, *obj_ptr);
rb_gc_handle_weak_references(*obj_ptr);
gc_mark_set_parent_invalid(objspace);
}

size_t capa = rb_darray_capa(objspace->weak_references);
Expand Down
4 changes: 3 additions & 1 deletion gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,9 @@ rb_gc_impl_init(void)
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MMTK_MAX_OBJ_SIZE));
// Pretend we have 5 size pools
rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(5));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(MMTK_HEAP_COUNT));
// TODO: correctly set RVALUE_OLD_AGE when we have generational GC support
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(0));
OBJ_FREEZE(gc_constants);
rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);

Expand Down
2 changes: 1 addition & 1 deletion parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -5149,7 +5149,7 @@ lambda : tLAMBDA[lpar]
CMDARG_POP();
$args = args_with_numbered(p, $args, max_numparam, it_id);
{
YYLTYPE loc = code_loc_gen(&@args, &@body);
YYLTYPE loc = code_loc_gen(&@lpar, &@body);
$$ = NEW_LAMBDA($args, $body->node, &loc, &@lpar, &$body->opening_loc, &$body->closing_loc);
nd_set_line(RNODE_LAMBDA($$)->nd_body, @body.end_pos.lineno);
nd_set_line($$, @args.end_pos.lineno);
Expand Down
7 changes: 0 additions & 7 deletions prism_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3284,13 +3284,6 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
scope->parameters = cast->parameters;
scope->body = cast->body;
scope->locals = cast->locals;

if (cast->parameters != NULL) {
scope->base.location.start = cast->parameters->location.start;
}
else {
scope->base.location.start = cast->operator_loc.end;
}
break;
}
case PM_MODULE_NODE: {
Expand Down
22 changes: 14 additions & 8 deletions proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,14 +1513,20 @@ proc_eq(VALUE self, VALUE other)
static VALUE
iseq_location(const rb_iseq_t *iseq)
{
VALUE loc[2];
VALUE loc[5];
int i = 0;

if (!iseq) return Qnil;
rb_iseq_check(iseq);
loc[0] = rb_iseq_path(iseq);
loc[1] = RB_INT2NUM(ISEQ_BODY(iseq)->location.first_lineno);
loc[i++] = rb_iseq_path(iseq);
const rb_code_location_t *cl = &ISEQ_BODY(iseq)->location.code_location;
loc[i++] = RB_INT2NUM(cl->beg_pos.lineno);
loc[i++] = RB_INT2NUM(cl->beg_pos.column);
loc[i++] = RB_INT2NUM(cl->end_pos.lineno);
loc[i++] = RB_INT2NUM(cl->end_pos.column);
RUBY_ASSERT_ALWAYS(i == numberof(loc));

return rb_ary_new4(2, loc);
return rb_ary_new_from_values(i, loc);
}

VALUE
Expand All @@ -1537,9 +1543,9 @@ rb_iseq_location(const rb_iseq_t *iseq)
* The returned Array contains:
* (1) the Ruby source filename
* (2) the line number where the definition starts
* (3) the column number where the definition starts
* (3) the position where the definition starts, in number of bytes from the start of the line
* (4) the line number where the definition ends
* (5) the column number where the definitions ends
* (5) the position where the definitions ends, in number of bytes from the start of the line
*
* This method will return +nil+ if the Proc was not defined in Ruby (i.e. native).
*/
Expand Down Expand Up @@ -3197,9 +3203,9 @@ rb_method_entry_location(const rb_method_entry_t *me)
* The returned Array contains:
* (1) the Ruby source filename
* (2) the line number where the definition starts
* (3) the column number where the definition starts
* (3) the position where the definition starts, in number of bytes from the start of the line
* (4) the line number where the definition ends
* (5) the column number where the definitions ends
* (5) the position where the definitions ends, in number of bytes from the start of the line
*
* This method will return +nil+ if the method was not defined in Ruby (i.e. native).
*/
Expand Down
16 changes: 11 additions & 5 deletions spec/ruby/core/method/source_location_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@
end

it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end

it "sets the last value to an Integer representing the line on which the method was defined" do
line = @method.source_location.last
line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 5
end

it "returns the last place the method was defined" do
MethodSpecs::SourceLocation.method(:redefined).source_location.last.should == 13
MethodSpecs::SourceLocation.method(:redefined).source_location[1].should == 13
end

it "returns the location of the original method even if it was aliased" do
MethodSpecs::SourceLocation.new.method(:aka).source_location.last.should == 17
MethodSpecs::SourceLocation.new.method(:aka).source_location[1].should == 17
end

it "works for methods defined with a block" do
Expand Down Expand Up @@ -108,7 +108,13 @@ def f
c = Class.new do
eval('def self.m; end', nil, "foo", 100)
end
c.method(:m).source_location.should == ["foo", 100]
location = c.method(:m).source_location
ruby_version_is(""..."4.1") do
location.should == ["foo", 100]
end
ruby_version_is("4.1") do
location.should == ["foo", 100, 0, 100, 15]
end
end

describe "for a Method generated by respond_to_missing?" do
Expand Down
51 changes: 32 additions & 19 deletions spec/ruby/core/proc/source_location_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,64 @@
end

it "sets the first value to the path of the file in which the proc was defined" do
file = @proc.source_location.first
file = @proc.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)

file = @proc_new.source_location.first
file = @proc_new.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)

file = @lambda.source_location.first
file = @lambda.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)

file = @method.source_location.first
file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
end

it "sets the last value to an Integer representing the line on which the proc was defined" do
line = @proc.source_location.last
it "sets the second value to an Integer representing the line on which the proc was defined" do
line = @proc.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 4

line = @proc_new.source_location.last
line = @proc_new.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 12

line = @lambda.source_location.last
line = @lambda.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 8

line = @method.source_location.last
line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 15
end

it "works even if the proc was created on the same line" do
proc { true }.source_location.should == [__FILE__, __LINE__]
Proc.new { true }.source_location.should == [__FILE__, __LINE__]
-> { true }.source_location.should == [__FILE__, __LINE__]
ruby_version_is(""..."4.1") do
proc { true }.source_location.should == [__FILE__, __LINE__]
Proc.new { true }.source_location.should == [__FILE__, __LINE__]
-> { true }.source_location.should == [__FILE__, __LINE__]
end
ruby_version_is("4.1") do
proc { true }.source_location.should == [__FILE__, __LINE__, 11, __LINE__, 19]
Proc.new { true }.source_location.should == [__FILE__, __LINE__, 15, __LINE__, 23]
-> { true }.source_location.should == [__FILE__, __LINE__, 6, __LINE__, 17]
end
end

it "returns the first line of a multi-line proc (i.e. the line containing 'proc do')" do
ProcSpecs::SourceLocation.my_multiline_proc.source_location.last.should == 20
ProcSpecs::SourceLocation.my_multiline_proc_new.source_location.last.should == 34
ProcSpecs::SourceLocation.my_multiline_lambda.source_location.last.should == 27
ProcSpecs::SourceLocation.my_multiline_proc.source_location[1].should == 20
ProcSpecs::SourceLocation.my_multiline_proc_new.source_location[1].should == 34
ProcSpecs::SourceLocation.my_multiline_lambda.source_location[1].should == 27
end

it "returns the location of the proc's body; not necessarily the proc itself" do
ProcSpecs::SourceLocation.my_detached_proc.source_location.last.should == 41
ProcSpecs::SourceLocation.my_detached_proc_new.source_location.last.should == 51
ProcSpecs::SourceLocation.my_detached_lambda.source_location.last.should == 46
ProcSpecs::SourceLocation.my_detached_proc.source_location[1].should == 41
ProcSpecs::SourceLocation.my_detached_proc_new.source_location[1].should == 51
ProcSpecs::SourceLocation.my_detached_lambda.source_location[1].should == 46
end

it "returns the same value for a proc-ified method as the method reports" do
Expand All @@ -86,6 +93,12 @@

it "works for eval with a given line" do
proc = eval('-> {}', nil, "foo", 100)
proc.source_location.should == ["foo", 100]
location = proc.source_location
ruby_version_is(""..."4.1") do
location.should == ["foo", 100]
end
ruby_version_is("4.1") do
location.should == ["foo", 100, 0, 100, 5]
end
end
end
18 changes: 12 additions & 6 deletions spec/ruby/core/unboundmethod/source_location_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
end

it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end

it "sets the last value to an Integer representing the line on which the method was defined" do
line = @method.source_location.last
it "sets the second value to an Integer representing the line on which the method was defined" do
line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 5
end

it "returns the last place the method was defined" do
UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location.last.should == 13
UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location[1].should == 13
end

it "returns the location of the original method even if it was aliased" do
UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location.last.should == 17
UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location[1].should == 17
end

it "works for define_method methods" do
Expand Down Expand Up @@ -54,6 +54,12 @@
c = Class.new do
eval('def m; end', nil, "foo", 100)
end
c.instance_method(:m).source_location.should == ["foo", 100]
location = c.instance_method(:m).source_location
ruby_version_is(""..."4.1") do
location.should == ["foo", 100]
end
ruby_version_is("4.1") do
location.should == ["foo", 100, 0, 100, 10]
end
end
end
2 changes: 1 addition & 1 deletion test/ruby/test_ast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,7 @@ def test_error_tolerant_end_is_short_for_do_LAMBDA
args: nil
body:
(LAMBDA@1:0-2:3
(SCOPE@1:2-2:3
(SCOPE@1:0-2:3
tbl: []
args:
(ARGS@1:2-1:2
Expand Down
Loading