diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0a4e19e229b9a0..2ed27e278b1dd4 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -177,30 +177,30 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ failure() }} - # make-ibm: - # strategy: - # matrix: - # include: - # - test_task: check - # os: ubuntu-24.04-ppc64le - # - test_task: check - # os: ubuntu-24.04-s390x - # fail-fast: false - - # env: *make-env - - # runs-on: ${{ matrix.os }} - - # if: >- - # ${{github.repository == 'ruby/ruby' - # && !(false - # || contains(github.event.head_commit.message, '[DOC]') - # || contains(github.event.pull_request.title, '[DOC]') - # || contains(github.event.pull_request.labels.*.name, 'Documentation') - # || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') - # )}} - - # steps: *make-steps + make-ibm: + strategy: + matrix: + include: + - test_task: check + os: ubuntu-24.04-ppc64le + - test_task: check + os: ubuntu-24.04-s390x + fail-fast: false + + env: *make-env + + runs-on: ${{ matrix.os }} + + if: >- + ${{github.repository == 'ruby/ruby' + && !(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') + )}} + + steps: *make-steps # Separated from `make` job to avoid making it a required status check ruby-bench: diff --git a/depend b/depend index 7525bcf396b901..978ac438b903d6 100644 --- a/depend +++ b/depend @@ -11091,6 +11091,7 @@ pathname.$(OBJEXT): {$(VPATH)}st.h pathname.$(OBJEXT): {$(VPATH)}subst.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/api_node.$(OBJEXT): $(hdrdir)/ruby/version.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h @@ -11286,6 +11287,7 @@ prism/api_node.$(OBJEXT): {$(VPATH)}st.h prism/api_node.$(OBJEXT): {$(VPATH)}subst.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/version.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/api_pack.c prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h @@ -11496,6 +11498,7 @@ prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/extension.$(OBJEXT): $(hdrdir)/ruby.h prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/extension.$(OBJEXT): $(hdrdir)/ruby/version.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h @@ -11885,6 +11888,7 @@ prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h prism_init.$(OBJEXT): $(hdrdir)/ruby.h prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism_init.$(OBJEXT): $(hdrdir)/ruby/version.h prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 639740e46b6b04..3cf9fbe8bf03aa 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -1077,7 +1077,7 @@ def converge_specs(specs) end end - if parent_dep && parent_dep.source.is_a?(Source::Path) + if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any? replacement_source = parent_dep.source else replacement_source = sources.get(lockfile_source) diff --git a/parse.y b/parse.y index 7ca1197b37339a..b874e4f8dc9371 100644 --- a/parse.y +++ b/parse.y @@ -13839,7 +13839,9 @@ value_expr_check(struct parser_params *p, NODE *node) case NODE_RESCUE: /* void only if all children are void */ vn = RNODE_RESCUE(node)->nd_head; - if (!vn || !(vn = value_expr_check(p, vn))) return NULL; + if (!vn || !(vn = value_expr_check(p, vn))) { + if (!RNODE_RESCUE(node)->nd_else) return NULL; + } if (!void_node) void_node = vn; for (NODE *r = RNODE_RESCUE(node)->nd_resq; r; r = RNODE_RESBODY(r)->nd_next) { if (!nd_type_p(r, NODE_RESBODY)) { @@ -13847,8 +13849,7 @@ value_expr_check(struct parser_params *p, NODE *node) return NULL; } if (!(vn = value_expr_check(p, RNODE_RESBODY(r)->nd_body))) { - void_node = 0; - break; + return NULL; } if (!void_node) void_node = vn; } @@ -13863,19 +13864,43 @@ value_expr_check(struct parser_params *p, NODE *node) case NODE_RETRY: goto found; - case NODE_CASE3: - if (!RNODE_CASE3(node)->nd_body || !nd_type_p(RNODE_CASE3(node)->nd_body, NODE_IN)) { - compile_error(p, "unexpected node"); - return NULL; + case NODE_CASE: + case NODE_CASE2: + for (node = RNODE_CASE(node)->nd_body; + node && nd_type_p(node, NODE_WHEN); + node = RNODE_WHEN(node)->nd_next) { + if (!(vn = value_expr_check(p, RNODE_WHEN(node)->nd_body))) { + return NULL; + } + if (!void_node) void_node = vn; } - if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) { - return NULL; + break; + + case NODE_CASE3: + { + NODE *in = RNODE_CASE3(node)->nd_body; + if (!in || !nd_type_p(in, NODE_IN)) { + compile_error(p, "unexpected node"); + return NULL; + } + if (!RNODE_IN(in)->nd_body) { + /* single line pattern matching with "=>" operator */ + goto found; + } + do { + vn = value_expr_check(p, RNODE_IN(in)->nd_body); + if (!vn) return NULL; + if (!void_node) void_node = vn; + in = RNODE_IN(in)->nd_next; + } while (in && nd_type_p(in, NODE_IN)); + node = in; /* else */ } - /* single line pattern matching with "=>" operator */ - goto found; + break; case NODE_BLOCK: while (RNODE_BLOCK(node)->nd_next) { + vn = value_expr_check(p, RNODE_BLOCK(node)->nd_head); + if (vn) return vn; node = RNODE_BLOCK(node)->nd_next; } node = RNODE_BLOCK(node)->nd_head; diff --git a/rubyparser.h b/rubyparser.h index 5af8f6db62c308..36a2dc30a6f8b2 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -289,25 +289,7 @@ typedef struct RNode_CASE { struct RNode *nd_body; rb_code_location_t case_keyword_loc; rb_code_location_t end_keyword_loc; -} rb_node_case_t; - -typedef struct RNode_CASE2 { - NODE node; - - struct RNode *nd_head; - struct RNode *nd_body; - rb_code_location_t case_keyword_loc; - rb_code_location_t end_keyword_loc; -} rb_node_case2_t; - -typedef struct RNode_CASE3 { - NODE node; - - struct RNode *nd_head; - struct RNode *nd_body; - rb_code_location_t case_keyword_loc; - rb_code_location_t end_keyword_loc; -} rb_node_case3_t; +} rb_node_case_t, rb_node_case2_t, rb_node_case3_t; typedef struct RNode_WHEN { NODE node; diff --git a/spec/bundled_gems_spec.rb b/spec/bundled_gems_spec.rb index d985ddad412e01..c02ae818e0d064 100644 --- a/spec/bundled_gems_spec.rb +++ b/spec/bundled_gems_spec.rb @@ -280,7 +280,7 @@ def my # Original issue is childprocess 5.0.0 and logger. build_lib "fileutils2", "5.0.0" do |s| # bootsnap expand required feature to full path - rubylibpath = File.expand_path(File.join(__dir__, "..", "lib")) + rubylibpath = File.realpath(File.join(__dir__, "..", "lib")) s.write "lib/fileutils2.rb", "require '#{rubylibpath}/fileutils'" end diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 69b0816a18999e..c72a2b982a99ec 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1236,4 +1236,78 @@ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2") end end + + context "when a path gem has a transitive dependency that does not exist in the path source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_lib "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", path: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "path@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end + + context "when a git gem has a transitive dependency that does not exist in the git source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_git "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", git: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "git@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end end diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index a79e33fbb01684..0fbeb484f0ee8e 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -21,7 +21,7 @@ # If we use shared GEM_HOME and install multiple versions, it may cause # unexpected test failures. -gem "diff-lcs" +gem "diff-lcs", "< 2.0" require "rspec/core" require "rspec/expectations" diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 5065a1db332a54..e868967e8b7927 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2013,12 +2013,69 @@ def foo(*args) = super assert_equal(1, b.new.foo(1), bug21256) end + BUG_21669 = '[Bug #21669]' + + def test_value_expr_in_block + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.1") + {# + x = begin + return + "NG" + end + }; + end + def test_value_expr_in_condition mesg = /void value expression/ assert_syntax_error("tap {a = (true ? next : break)}", mesg) assert_valid_syntax("tap {a = (true ? true : break)}") assert_valid_syntax("tap {a = (break if false)}") assert_valid_syntax("tap {a = (break unless true)}") + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.4") + {# + x = if rand < 0.5 + return + else + return + end + }; + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.2") + {# + x = if rand < 0.5 + return + "NG" + else + return + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 2.3") + {# + x = begin + return if true + "OK" + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}") + {# + x = if true + return "NG" + else + "OK" + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}") + {# + x = if false + "OK" + else + return "NG" + end + }; end def test_value_expr_in_singleton @@ -2026,6 +2083,67 @@ def test_value_expr_in_singleton assert_syntax_error("class << (return); end", mesg) end + def test_value_expr_in_rescue + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 1.1") + {# + x = begin + raise + return + rescue + "OK" + else + return + end + }; + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.2") + {# + x = begin + foo + rescue + return + else + return + end + }; + end + + def test_value_expr_in_case + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case a + when 1; return + when 2; return + else return + end + }; + end + + def test_value_expr_in_case2 + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case + when 1; return + when 2; return + else return + end + }; + end + + def test_value_expr_in_case3 + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case a + in 1; return + in 2; return + else return + end + }; + end + def test_tautological_condition assert_valid_syntax("def f() return if false and invalid; nil end") assert_valid_syntax("def f() return unless true or invalid; nil end") diff --git a/tool/ifchange b/tool/ifchange index 9e4a89533c0f95..2a5f3db522b260 100755 --- a/tool/ifchange +++ b/tool/ifchange @@ -1,7 +1,8 @@ #!/bin/sh # usage: ifchange target temporary -# Used in generating revision.h via Makefiles. +# Used in generating various files such as rbconfig.rb, revision.h, +# etc. via Makefiles. help() { cat <= n, msg end diff --git a/tool/test/testunit/test_minitest_unit.rb b/tool/test/testunit/test_minitest_unit.rb index 84b6cf688c7b25..7f53e4b7dde59d 100644 --- a/tool/test/testunit/test_minitest_unit.rb +++ b/tool/test/testunit/test_minitest_unit.rb @@ -646,7 +646,7 @@ def test_delta_consistency def test_assert_in_delta_triggered x = "1.0e-06" - util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do + util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_delta 0.0, 1.0 / 1000, 0.000001 end end @@ -678,7 +678,7 @@ def test_epsilon_consistency end def test_assert_in_epsilon_triggered - util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.' do + util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.', strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_epsilon 10000, 9990 end end @@ -686,7 +686,7 @@ def test_assert_in_epsilon_triggered def test_assert_in_epsilon_triggered_negative_case x = "0.100000xxx" y = "0.1" - util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}." do + util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_epsilon(-1.1, -1, 0.1) end end @@ -1352,7 +1352,7 @@ def test_test3; assert "does not matter" end assert_equal expected, sample_test_case.test_methods.sort end - def assert_triggered expected, klass = Test::Unit::AssertionFailedError + def assert_triggered expected, klass = Test::Unit::AssertionFailedError, strip: nil e = assert_raise klass do yield end @@ -1360,6 +1360,7 @@ def assert_triggered expected, klass = Test::Unit::AssertionFailedError msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, '(oid=N)') msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform + msg.gsub!(strip, '') if strip assert_equal expected, msg end