diff --git a/.rdoc_options b/.rdoc_options index 38dca221112c53..591ddf58897595 100644 --- a/.rdoc_options +++ b/.rdoc_options @@ -10,6 +10,7 @@ rdoc_include: exclude: - \.gemspec\z +- lib/set/subclass_compatible.rb generator_name: aliki diff --git a/defs/jit.mk b/defs/jit.mk index e893098ca26486..42b56c4cd928b6 100644 --- a/defs/jit.mk +++ b/defs/jit.mk @@ -1,4 +1,9 @@ # Make recipes that deal with the rust code of YJIT and ZJIT. +# +# $(gnumake_recursive) adds the '+' prefix to pass down GNU make's +# jobserver resources to cargo/rustc as rust-lang.org recommends. +# Without it, certain make version trigger a warning. It does not +# add the prefix when `make --dry-run` so dry runs are indeed dry. ifneq ($(JIT_CARGO_SUPPORT),no) @@ -25,7 +30,7 @@ $(RUST_LIB): $(srcdir)/ruby.rs elif [ '$(YJIT_SUPPORT)' != no ]; then \ echo 'building YJIT ($(JIT_CARGO_SUPPORT) mode)'; \ fi - +$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \ + $(gnumake_recursive)$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \ CARGO_TERM_PROGRESS_WHEN='never' \ MACOSX_DEPLOYMENT_TARGET=11.0 \ $(CARGO) $(CARGO_VERBOSE) build --manifest-path '$(top_srcdir)/Cargo.toml' $(CARGO_BUILD_ARGS) @@ -34,7 +39,7 @@ else ifneq ($(strip $(RLIB_DIR)),) # combo build $(RUST_LIB): $(srcdir)/ruby.rs $(ECHO) 'building $(@F)' - $(Q) $(RUSTC) --edition=2024 \ + $(gnumake_recursive)$(Q) $(RUSTC) --edition=2024 \ '-L$(@D)' \ --extern=yjit \ --extern=zjit \ @@ -50,7 +55,7 @@ $(YJIT_RLIB): $(JIT_RLIB) $(ZJIT_RLIB): $(JIT_RLIB) $(JIT_RLIB): $(ECHO) 'building $(@F)' - $(Q) $(RUSTC) --crate-name=jit \ + $(gnumake_recursive)$(Q) $(RUSTC) --crate-name=jit \ --edition=2024 \ $(JIT_RUST_FLAGS) \ '--out-dir=$(@D)' \ diff --git a/gc.c b/gc.c index 5a14cb3675032d..d229c1f5aba254 100644 --- a/gc.c +++ b/gc.c @@ -1537,34 +1537,26 @@ os_obj_of(VALUE of) * Ruby process. If module is specified, calls the block * for only those classes or modules that match (or are a subclass of) * module. Returns the number of objects found. Immediate - * objects (Fixnums, Symbols - * true, false, and nil) are - * never returned. In the example below, #each_object returns both - * the numbers we defined and several constants defined in the Math - * module. + * objects (such as Fixnums, static Symbols + * true, false and nil) are + * never returned. * * If no block is given, an enumerator is returned instead. * - * a = 102.7 - * b = 95 # Won't be returned - * c = 12345678987654321 - * count = ObjectSpace.each_object(Numeric) {|x| p x } + * Job = Class.new + * jobs = [Job.new, Job.new] + * count = ObjectSpace.each_object(Job) {|x| p x } * puts "Total count: #{count}" * * produces: * - * 12345678987654321 - * 102.7 - * 2.71828182845905 - * 3.14159265358979 - * 2.22044604925031e-16 - * 1.7976931348623157e+308 - * 2.2250738585072e-308 - * Total count: 7 + * # + * # + * Total count: 2 * - * Due to a current known Ractor implementation issue, this method will not yield - * Ractor-unshareable objects in multi-Ractor mode (when - * Ractor.new has been called within the process at least once). + * Due to a current Ractor implementation issue, this method does not yield + * Ractor-unshareable objects when the process is in multi-Ractor mode. Multi-ractor + * mode is enabled when Ractor.new has been called for the first time. * See https://bugs.ruby-lang.org/issues/19387 for more information. * * a = 12345678987654321 # shareable diff --git a/include/ruby/internal/ctype.h b/include/ruby/internal/ctype.h index 0f7ca6c51635d0..93e92801fcc5a3 100644 --- a/include/ruby/internal/ctype.h +++ b/include/ruby/internal/ctype.h @@ -498,7 +498,7 @@ RBIMPL_ATTR_ARTIFICIAL() * Our own locale-insensitive version of `tolower(3)`. * * @param[in] c Byte in question to convert. - * @retval c The byte is not listed in in IEEE 1003.1 section + * @retval c The byte is not listed in IEEE 1003.1 section * 7.3.1.1 "upper". * @retval otherwise Byte converted using the map defined in IEEE 1003.1 * section 7.3.1 "tolower". diff --git a/include/ruby/internal/symbol.h b/include/ruby/internal/symbol.h index 569bf215a2df85..858c5e290f6463 100644 --- a/include/ruby/internal/symbol.h +++ b/include/ruby/internal/symbol.h @@ -187,7 +187,7 @@ ID rb_check_id(volatile VALUE *namep); * * :FIXME: Can anyone tell us what is the difference between this one and * rb_intern_str()? As far as @shyouhei reads the implementation it seems what - * rb_to_id() does is is just waste some CPU time, then call rb_intern_str(). + * rb_to_id() does is just waste some CPU time, then call rb_intern_str(). * He hopes he is wrong. */ ID rb_to_id(VALUE str); diff --git a/ractor_sync.c b/ractor_sync.c index 57ae13e88de50f..8c7c144c3fda97 100644 --- a/ractor_sync.c +++ b/ractor_sync.c @@ -699,7 +699,12 @@ ractor_sync_free(rb_ractor_t *r) static size_t ractor_sync_memsize(const rb_ractor_t *r) { - return st_table_size(r->sync.ports); + if (r->sync.ports) { + return st_table_size(r->sync.ports); + } + else { + return 0; + } } static void diff --git a/set.c b/set.c index 6d200b5dfa1495..734a6ecaea2107 100644 --- a/set.c +++ b/set.c @@ -495,11 +495,11 @@ set_initialize_with_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set)) * If a block is given, the elements of enum are preprocessed by the * given block. * - * Set.new([1, 2]) #=> # - * Set.new([1, 2, 1]) #=> # - * Set.new([1, 'c', :s]) #=> # - * Set.new(1..5) #=> # - * Set.new([1, 2, 3]) { |x| x * x } #=> # + * Set.new([1, 2]) #=> Set[1, 2] + * Set.new([1, 2, 1]) #=> Set[1, 2] + * Set.new([1, 'c', :s]) #=> Set[1, "c", :s] + * Set.new(1..5) #=> Set[1, 2, 3, 4, 5] + * Set.new([1, 2, 3]) { |x| x * x } #=> Set[1, 4, 9] */ static VALUE set_i_initialize(int argc, VALUE *argv, VALUE set) @@ -595,11 +595,11 @@ set_inspect(VALUE set, VALUE dummy, int recur) * Returns a new string containing the set entries: * * s = Set.new - * s.inspect # => "#" + * s.inspect # => "Set[]" * s.add(1) - * s.inspect # => "#" + * s.inspect # => "Set[1]" * s.add(2) - * s.inspect # => "#" + * s.inspect # => "Set[1, 2]" * * Related: see {Methods for Converting}[rdoc-ref:Set@Methods+for+Converting]. */ @@ -650,11 +650,11 @@ set_i_to_a(VALUE set) * call-seq: * to_set(klass = Set, *args, &block) -> self or new_set * - * Returns self if receiver is an instance of +Set+ and no arguments or - * block are given. Otherwise, converts the set to another with - * klass.new(self, *args, &block). + * Without arguments, returns +self+ (for duck-typing in methods that + * accept "set, or set-convertible" arguments). * - * In subclasses, returns `klass.new(self, *args, &block)` unless overridden. + * A form with arguments is _deprecated_. It converts the set to another + * with klass.new(self, *args, &block). */ static VALUE set_i_to_set(int argc, VALUE *argv, VALUE set) @@ -700,9 +700,9 @@ set_i_join(int argc, VALUE *argv, VALUE set) * Adds the given object to the set and returns self. Use `merge` to * add many elements at once. * - * Set[1, 2].add(3) #=> # - * Set[1, 2].add([3, 4]) #=> # - * Set[1, 2].add(2) #=> # + * Set[1, 2].add(3) #=> Set[1, 2, 3] + * Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]] + * Set[1, 2].add(2) #=> Set[1, 2] */ static VALUE set_i_add(VALUE set, VALUE item) @@ -726,8 +726,8 @@ set_i_add(VALUE set, VALUE item) * Adds the given object to the set and returns self. If the object is * already in the set, returns nil. * - * Set[1, 2].add?(3) #=> # - * Set[1, 2].add?([3, 4]) #=> # + * Set[1, 2].add?(3) #=> Set[1, 2, 3] + * Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]] * Set[1, 2].add?(2) #=> nil */ static VALUE @@ -856,9 +856,9 @@ set_classify_i(st_data_t key, st_data_t tmp) * * files = Set.new(Dir.glob("*.rb")) * hash = files.classify { |f| File.mtime(f).year } - * hash #=> {2000 => #, - * # 2001 => #, - * # 2002 => #} + * hash #=> {2000 => Set["a.rb", "b.rb"], + * # 2001 => Set["c.rb", "d.rb", "e.rb"], + * # 2002 => Set["f.rb"]} * * Returns an enumerator if no block is given. */ @@ -959,10 +959,10 @@ static void set_merge_enum_into(VALUE set, VALUE arg); * * numbers = Set[1, 3, 4, 6, 9, 10, 11] * set = numbers.divide { |i,j| (i - j).abs == 1 } - * set #=> #, - * # #, - * # #}> - * # #, + * set #=> Set[Set[1], + * # Set[3, 4], + * # Set[6], + * # Set[9, 10, 11]] * * Returns an enumerator if no block is given. */ @@ -993,9 +993,9 @@ set_clear_i(st_data_t key, st_data_t dummy) * * Removes all elements and returns self. * - * set = Set[1, 'c', :s] #=> # - * set.clear #=> # - * set #=> # + * set = Set[1, 'c', :s] #=> Set[1, "c", :s] + * set.clear #=> Set[] + * set #=> Set[] */ static VALUE set_i_clear(VALUE set) @@ -1043,8 +1043,8 @@ set_intersection_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, data)) * Returns a new set containing elements common to the set and the given * enumerable object. * - * Set[1, 3, 5] & Set[3, 2, 1] #=> # - * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> # + * Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1] + * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"] */ static VALUE set_i_intersection(VALUE set, VALUE other) @@ -1285,8 +1285,8 @@ set_xor_i(st_data_t key, st_data_t data) * given enumerable object. (set ^ enum) is equivalent to * ((set | enum) - (set & enum)). * - * Set[1, 2] ^ Set[2, 3] #=> # - * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> # + * Set[1, 2] ^ Set[2, 3] #=> Set[3, 1] + * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"] */ static VALUE set_i_xor(VALUE set, VALUE other) @@ -1312,8 +1312,8 @@ set_i_xor(VALUE set, VALUE other) * Returns a new set built by merging the set and the elements of the * given enumerable object. * - * Set[1, 2, 3] | Set[2, 4, 5] #=> # - * Set[1, 5, 'z'] | (1..6) #=> # + * Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5] + * Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6] */ static VALUE set_i_union(VALUE set, VALUE other) @@ -1371,8 +1371,8 @@ set_i_subtract(VALUE set, VALUE other) * Returns a new set built by duplicating the set, removing every * element that appears in the given enumerable object. * - * Set[1, 3, 5] - Set[1, 5] #=> # - * Set['a', 'b', 'z'] - ['a', 'c'] #=> # + * Set[1, 3, 5] - Set[1, 5] #=> Set[3] + * Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"] */ static VALUE set_i_difference(VALUE set, VALUE other) @@ -1488,9 +1488,9 @@ set_i_select(VALUE set) * Replaces the contents of the set with the contents of the given * enumerable object and returns self. * - * set = Set[1, 'c', :s] #=> # - * set.replace([1, 2]) #=> # - * set #=> # + * set = Set[1, 'c', :s] #=> Set[1, "c", :s] + * set.replace([1, 2]) #=> Set[1, 2] + * set #=> Set[1, 2] */ static VALUE set_i_replace(VALUE set, VALUE other) @@ -1766,7 +1766,7 @@ set_i_disjoint(VALUE set, VALUE other) * set <=> other -> -1, 0, 1, or nil * * Returns 0 if the set are equal, -1 / 1 if the set is a - * proper subset / superset of the given set, or or nil if + * proper subset / superset of the given set, or nil if * they both have unique elements. */ static VALUE @@ -1992,10 +1992,10 @@ rb_set_size(VALUE set) * duplicates. It is a hybrid of Array's intuitive inter-operation * facilities and Hash's fast lookup. * - * Set is easy to use with Enumerable objects (implementing `each`). + * Set is easy to use with Enumerable objects (implementing #each). * Most of the initializer methods and binary operators accept generic * Enumerable objects besides sets and arrays. An Enumerable object - * can be converted to Set using the `to_set` method. + * can be converted to Set using the +to_set+ method. * * Set uses a data structure similar to Hash for storage, except that * it only has keys and no values. @@ -2019,11 +2019,11 @@ rb_set_size(VALUE set) * * == Example * - * s1 = Set[1, 2] #=> # - * s2 = [1, 2].to_set #=> # + * s1 = Set[1, 2] #=> Set[1, 2] + * s2 = [1, 2].to_set #=> Set[1, 2] * s1 == s2 #=> true - * s1.add("foo") #=> # - * s1.merge([2, 6]) #=> # + * s1.add("foo") #=> Set[1, 2, "foo"] + * s1.merge([2, 6]) #=> Set[1, 2, "foo", 6] * s1.subset?(s2) #=> false * s2.subset?(s1) #=> true * @@ -2031,9 +2031,39 @@ rb_set_size(VALUE set) * * - Akinori MUSHA (current maintainer) * - * == What's Here + * == Inheriting from \Set * - * First, what's elsewhere. \Class \Set: + * Before Ruby 4.0 (released December 2025), \Set had a different, less + * efficient implementation. It was reimplemented in C, and the behavior + * of some of the core methods were adjusted. + * + * To keep backward compatibility, when a class is inherited from \Set, + * additional module +Set::SubclassCompatible+ is included, which makes + * the inherited class behavior, as well as internal method names, + * closer to what it was before Ruby 4.0. + * + * It can be easily seen, for example, in the #inspect method behavior: + * + * p Set[1, 2, 3] + * # prints "Set[1, 2, 3]" + * + * class MySet < Set + * end + * p MySet[1, 2, 3] + * # prints "#", like it was in Ruby 3.4 + * + * For new code, if backward compatibility is not necessary, + * it is recommended to instead inherit from +Set::CoreSet+, which + * avoids including the "compatibility" layer: + * + * class MyCoreSet < Set::CoreSet + * end + * p MyCoreSet[1, 2, 3] + * # prints "MyCoreSet[1, 2, 3]" + * + * == Set's methods + * + * First, what's elsewhere. \Class \Set: * * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here]. * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here], @@ -2045,16 +2075,15 @@ rb_set_size(VALUE set) * * Here, class \Set provides methods that are useful for: * - * - {Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array] * - {Creating a Set}[rdoc-ref:Set@Methods+for+Creating+a+Set] * - {Set Operations}[rdoc-ref:Set@Methods+for+Set+Operations] - * - {Comparing}[rdoc-ref:Array@Methods+for+Comparing] - * - {Querying}[rdoc-ref:Array@Methods+for+Querying] - * - {Assigning}[rdoc-ref:Array@Methods+for+Assigning] - * - {Deleting}[rdoc-ref:Array@Methods+for+Deleting] - * - {Converting}[rdoc-ref:Array@Methods+for+Converting] - * - {Iterating}[rdoc-ref:Array@Methods+for+Iterating] - * - {And more....}[rdoc-ref:Array@Other+Methods] + * - {Comparing}[rdoc-ref:Set@Methods+for+Comparing] + * - {Querying}[rdoc-ref:Set@Methods+for+Querying] + * - {Assigning}[rdoc-ref:Set@Methods+for+Assigning] + * - {Deleting}[rdoc-ref:Set@Methods+for+Deleting] + * - {Converting}[rdoc-ref:Set@Methods+for+Converting] + * - {Iterating}[rdoc-ref:Set@Methods+for+Iterating] + * - {And more....}[rdoc-ref:Set@Other+Methods] * * === Methods for Creating a \Set * diff --git a/yjit/yjit.mk b/yjit/yjit.mk index 22d256fee78c14..21fd96514bdca9 100644 --- a/yjit/yjit.mk +++ b/yjit/yjit.mk @@ -18,14 +18,14 @@ ifneq ($(strip $(YJIT_LIBS)),) yjit-libs: $(BUILD_YJIT_LIBS) $(BUILD_YJIT_LIBS): $(YJIT_SRC_FILES) $(ECHO) 'building Rust YJIT (release mode)' - $(Q) $(RUSTC) $(YJIT_RUSTC_ARGS) + $(gnumake_recursive)$(Q) $(RUSTC) $(YJIT_RUSTC_ARGS) else ifneq ($(strip $(RLIB_DIR)),) # combo build # Absolute path to avoid VPATH ambiguity YJIT_RLIB = $(TOP_BUILD_DIR)/$(RLIB_DIR)/libyjit.rlib $(YJIT_RLIB): $(YJIT_SRC_FILES) $(ECHO) 'building $(@F)' - $(Q) $(RUSTC) '-L$(@D)' --extern=jit $(YJIT_RUSTC_ARGS) + $(gnumake_recursive)$(Q) $(RUSTC) '-L$(@D)' --extern=jit $(YJIT_RUSTC_ARGS) $(RUST_LIB): $(YJIT_RLIB) endif # ifneq ($(strip $(YJIT_LIBS)),) diff --git a/zjit/zjit.mk b/zjit/zjit.mk index 2116775a91a182..58b45d87872d94 100644 --- a/zjit/zjit.mk +++ b/zjit/zjit.mk @@ -22,14 +22,14 @@ BUILD_ZJIT_LIBS = $(TOP_BUILD_DIR)/$(ZJIT_LIBS) ifneq ($(strip $(ZJIT_LIBS)),) $(BUILD_ZJIT_LIBS): $(ZJIT_SRC_FILES) $(ECHO) 'building Rust ZJIT (release mode)' - $(Q) $(RUSTC) $(ZJIT_RUSTC_ARGS) + $(gnumake_recursive)$(Q) $(RUSTC) $(ZJIT_RUSTC_ARGS) else ifneq ($(strip $(RLIB_DIR)),) # combo build # Absolute path to avoid VPATH ambiguity ZJIT_RLIB = $(TOP_BUILD_DIR)/$(RLIB_DIR)/libzjit.rlib $(ZJIT_RLIB): $(ZJIT_SRC_FILES) $(ECHO) 'building $(@F)' - $(Q) $(RUSTC) '-L$(@D)' --extern=jit $(ZJIT_RUSTC_ARGS) + $(gnumake_recursive)$(Q) $(RUSTC) '-L$(@D)' --extern=jit $(ZJIT_RUSTC_ARGS) $(RUST_LIB): $(ZJIT_RLIB) endif # ifneq ($(strip $(ZJIT_LIBS)),)