summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parse.y130
-rw-r--r--test/ruby/test_parse.rb11
-rw-r--r--vm.c1
3 files changed, 135 insertions, 7 deletions
diff --git a/parse.y b/parse.y
index 0e1ed592c7..664df9f542 100644
--- a/parse.y
+++ b/parse.y
@@ -10985,31 +10985,149 @@ mark_lvar_used(struct parser_params *p, NODE *rhs)
extern VALUE rb_mRubyVMFrozenCore;
static NODE *
-shareable_literal_constant(struct parser_params *p, NODE *value)
+shareable_literal_node(struct parser_params *p, NODE *value, const YYLTYPE *loc)
{
+ NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
+ return NEW_CALL(fcore, rb_intern("make_shareable"),
+ NEW_LIST(value, loc), loc);
+}
+
+static int is_static_content(NODE *node);
+
+static VALUE
+shareable_literal_value(NODE *node)
+{
+ if (!node) return Qnil;
+ enum node_type type = nd_type(node);
+ switch (type) {
+ case NODE_TRUE:
+ return Qtrue;
+ case NODE_FALSE:
+ return Qfalse;
+ case NODE_NIL:
+ return Qnil;
+ case NODE_LIT:
+ return node->nd_lit;
+ default:
+ return Qundef;
+ }
+}
+
+VALUE rb_ractor_make_shareable(VALUE obj);
+
+static NODE *
+shareable_literal_constant(struct parser_params *p, NODE *value, enum shareability shareable, const YYLTYPE *loc)
+{
+ VALUE lit;
+
+ if (!value) return 0;
+ enum node_type type = nd_type(value);
+ switch (type) {
+ case NODE_TRUE:
+ case NODE_FALSE:
+ case NODE_NIL:
+ case NODE_LIT:
+ case NODE_DSTR:
+ break;
+
+ case NODE_STR:
+ lit = rb_fstring(value->nd_lit);
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, lit);
+ break;
+
+ case NODE_ZLIST:
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, rb_ary_new());
+ break;
+
+ case NODE_LIST:
+ lit = rb_ary_new();
+ for (NODE *n = value; n; n = n->nd_next) {
+ NODE *elt = n->nd_head;
+ if (elt && !(elt = shareable_literal_constant(p, elt, shareable, &elt->nd_loc))) {
+ if (lit) {
+ rb_ary_clear(lit);
+ lit = Qfalse;
+ }
+ continue;
+ }
+ if (lit) {
+ VALUE e = shareable_literal_value(elt);
+ if (e != Qundef) {
+ rb_ary_push(lit, e);
+ }
+ else {
+ rb_ary_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ }
+ if (!lit) return 0;
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, rb_ractor_make_shareable(lit));
+ break;
+
+ case NODE_HASH:
+ if (!value->nd_brace) return 0;
+ lit = rb_hash_new();
+ for (NODE *n = value->nd_head; n; n = n->nd_next->nd_next) {
+ NODE *key = n->nd_head;
+ NODE *val = n->nd_next->nd_head;
+ if ((key && !(key = shareable_literal_constant(p, key, shareable, &key->nd_loc))) ||
+ (val && !(val = shareable_literal_constant(p, val, shareable, &val->nd_loc)))) {
+ if (lit) {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ continue;
+ }
+ if (lit) {
+ VALUE k = shareable_literal_value(key);
+ VALUE v = shareable_literal_value(val);
+ if (k != Qundef && v != Qundef) {
+ rb_hash_aset(lit, k, v);
+ }
+ else {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ }
+ if (!lit) return 0;
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, rb_ractor_make_shareable(lit));
+ break;
+
+ default:
+ if (shareable == shareable_literal)
+ yyerror1(loc, "unshareable expression");
+ return 0;
+ }
return value;
}
static NODE *
shareable_constant_value(struct parser_params *p, NODE *value, enum shareability shareable, const YYLTYPE *loc)
{
+ if (!value) return 0;
switch (shareable) {
case shareable_none:
return value;
case shareable_literal:
- return shareable_literal_constant(p, value);
-
case shareable_everything:
+ {
+ NODE *lit = shareable_literal_constant(p, value, shareable, loc);
+ if (lit) return lit;
+ }
break;
default:
UNREACHABLE_RETURN(0);
}
- NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
- return NEW_CALL(fcore, rb_intern("make_shareable"),
- NEW_LIST(value, loc), loc);
+ return shareable_literal_node(p, value, loc);
}
static NODE *
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb
index 61551a2c96..80debd7699 100644
--- a/test/ruby/test_parse.rb
+++ b/test/ruby/test_parse.rb
@@ -1187,11 +1187,14 @@ x = __ENCODING__
A = [[1]]
# shareable_constant_value: none
B = [[2]]
+ # shareable_constant_value: literal
+ C = [["shareable", "constant#{nil}"]]
- [A, B]
+ [A, B, C]
end;
assert_send([Ractor, :shareable?, a])
assert_not_send([Ractor, :shareable?, b])
+ assert_send([Ractor, :shareable?, c])
assert_equal([1], a[0])
assert_send([Ractor, :shareable?, a[0]])
a, b = Class.new.class_eval("#{<<~"begin;"}\n#{<<~'end;'}")
@@ -1208,6 +1211,12 @@ x = __ENCODING__
assert_not_send([Ractor, :shareable?, b])
assert_equal([1], a[0])
assert_send([Ractor, :shareable?, a[0]])
+
+ assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /unshareable expression/)
+ begin;
+ # shareable_constant_value: literal
+ C = ["Not " + "shareable"]
+ end;
end
=begin
diff --git a/vm.c b/vm.c
index bc57caf16a..c618b796cc 100644
--- a/vm.c
+++ b/vm.c
@@ -995,6 +995,7 @@ collect_outer_variable_names(ID id, VALUE val, void *ptr)
}
VALUE rb_ractor_error_class(void);
+VALUE rb_ractor_make_shareable(VALUE obj);
static const rb_env_t *
env_copy(const VALUE *src_ep, VALUE read_only_variables)