diff --git a/language/fixtures/variables.rb b/language/fixtures/variables.rb index 527caa7a7..3c9271edc 100644 --- a/language/fixtures/variables.rb +++ b/language/fixtures/variables.rb @@ -154,4 +154,46 @@ class Node attr_accessor :left, :right end end + + module RactorAccess + singleton_class.attr_accessor :ivar + + class << self + def run(code_str) + require_path = File.expand_path(__FILE__) + + code = <<~RUBY + require_relative "#{require_path}" + + puts #{code_str} + RUBY + + ruby_exe(code).chomp + end + + def read_in_ractor(shareable = true) + run_in_ractor(shareable, :read) + end + + def write_in_ractor(shareable = true) + run_in_ractor(shareable, :write) + end + + def run_in_ractor(shareable, type) + @ivar = shareable ? 3 : "3" + + r = Ractor.new(type) do |type| + if type == :read + RactorAccess.ivar + else + RactorAccess.ivar = 4 + end + rescue => e + e.class.name + end + + r.take + end + end + end end diff --git a/language/variables_spec.rb b/language/variables_spec.rb index 23c2cdb55..771353761 100644 --- a/language/variables_spec.rb +++ b/language/variables_spec.rb @@ -937,3 +937,58 @@ def obj.foobar; $specs_uninitialized_global_variable_lazy ||= 42; end end end end + +describe "Module instance variables within Ractors" do + context "when the instance variable is shareable" do + ruby_version_is ""..."3.1" do + it "raises Isolation error if read from a non-main Ractor" do + result = VariablesSpecs::RactorAccess.run("VariablesSpecs::RactorAccess.read_in_ractor") + result.should == "Ractor::IsolationError" + end + end + + ruby_version_is "3.1" do + it "can be read from a non-main Ractor" do + result = VariablesSpecs::RactorAccess.run("VariablesSpecs::RactorAccess.read_in_ractor") + result.should == "3" + end + end + + it "raises Isolation error if written to in a non-main Ractor" do + result = VariablesSpecs::RactorAccess.run("VariablesSpecs::RactorAccess.write_in_ractor") + result.should == "Ractor::IsolationError" + end + + it "raises no error if read/written in the main Ractor" do + code = <<~RUBY + VariablesSpecs::RactorAccess.ivar = 5 + VariablesSpecs::RactorAccess.ivar + RUBY + + result = VariablesSpecs::RactorAccess.run(code) + result.should == "5" + end + end + + context "when the instance variable is not shareable" do + it "raises Isolation error if read from a non-main Ractor" do + result = VariablesSpecs::RactorAccess.run("VariablesSpecs::RactorAccess.read_in_ractor(false)") + result.should == "Ractor::IsolationError" + end + + it "raises Isolation error if written to in a non-main Ractor" do + result = VariablesSpecs::RactorAccess.run("VariablesSpecs::RactorAccess.write_in_ractor(false)") + result.should == "Ractor::IsolationError" + end + + it "raises no error if read/written in the main Ractor" do + code = <<~RUBY + VariablesSpecs::RactorAccess.ivar = 5 + VariablesSpecs::RactorAccess.ivar + RUBY + + result = VariablesSpecs::RactorAccess.run(code) + result.should == "5" + end + end +end