[前][次][番号順一覧][スレッド一覧]

ruby-changes:64498

From: Nobuyoshi <ko1@a...>
Date: Wed, 23 Dec 2020 13:50:59 +0900 (JST)
Subject: [ruby-changes:64498] 7a094146e6 (master): Changed shareable literal semantics [Feature #17397]

https://git.ruby-lang.org/ruby.git/commit/?id=7a094146e6

From 7a094146e6ef38453a7e475450d90a9c83ea2277 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Sat, 19 Dec 2020 20:42:58 +0900
Subject: Changed shareable literal semantics [Feature #17397]

When `literal`, check if the literal about to be assigned to a
constant is ractor-shareable, otherwise raise `Ractor::Error` at
runtime instead of `SyntaxError`.

diff --git a/parse.y b/parse.y
index b3f07c3..50d24df 100644
--- a/parse.y
+++ b/parse.y
@@ -11008,16 +11008,61 @@ mark_lvar_used(struct parser_params *p, NODE *rhs) https://github.com/ruby/ruby/blob/trunk/parse.y#L11008
     }
 }
 
+static NODE *
+const_decl_path(struct parser_params *p, NODE **dest)
+{
+    NODE *n = *dest;
+    if (nd_type(n) != NODE_CALL) {
+	const YYLTYPE *loc = &n->nd_loc;
+	VALUE path;
+	if (n->nd_vid) {
+	     path = rb_id2str(n->nd_vid);
+	}
+	else {
+	    n = n->nd_else;
+	    path = rb_ary_new();
+	    for (; n && nd_type(n) == NODE_COLON2; n = n->nd_head) {
+		rb_ary_push(path, rb_id2str(n->nd_mid));
+	    }
+	    if (n && nd_type(n) == NODE_CONST) {
+		// Const::Name
+		rb_ary_push(path, rb_id2str(n->nd_vid));
+	    }
+	    else if (n && nd_type(n) == NODE_COLON3) {
+		// ::Const::Name
+		rb_ary_push(path, rb_str_new(0, 0));
+	    }
+	    else {
+		// expression::Name
+		rb_ary_push(path, rb_str_new_cstr("..."));
+	    }
+	    path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
+	    path = rb_fstring(path);
+	}
+	*dest = n = NEW_LIT(path, loc);
+    }
+    return n;
+}
+
 extern VALUE rb_mRubyVMFrozenCore;
 
 static NODE *
-shareable_literal_node(struct parser_params *p, NODE *value, const YYLTYPE *loc)
+make_shareable_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 NODE *
+ensure_shareable_node(struct parser_params *p, NODE **dest, NODE *value, const YYLTYPE *loc)
+{
+    NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
+    NODE *args = NEW_LIST(value, loc);
+    args = list_append(p, args, const_decl_path(p, dest));
+    return NEW_CALL(fcore, rb_intern("ensure_shareable"), args, loc);
+}
+
 static int is_static_content(NODE *node);
 
 static VALUE
@@ -11039,15 +11084,19 @@ shareable_literal_value(NODE *node) https://github.com/ruby/ruby/blob/trunk/parse.y#L11084
     }
 }
 
+#ifndef SHAREABLE_BARE_EXPRESSION
+#define SHAREABLE_BARE_EXPRESSION 0
+#endif
+
 VALUE rb_ractor_make_shareable(VALUE obj);
 
 static NODE *
 shareable_literal_constant(struct parser_params *p, enum shareability shareable,
-			   NODE *value, const YYLTYPE *loc, size_t level)
+			   NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
 {
 # define shareable_literal_constant_next(n) \
-    shareable_literal_constant(p, shareable, (n), &(n)->nd_loc, level+1)
-    VALUE lit;
+    shareable_literal_constant(p, shareable, dest, (n), &(n)->nd_loc, level+1)
+    VALUE lit = Qnil;
 
     if (!value) return 0;
     enum node_type type = nd_type(value);
@@ -11056,44 +11105,52 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable, https://github.com/ruby/ruby/blob/trunk/parse.y#L11105
       case NODE_FALSE:
       case NODE_NIL:
       case NODE_LIT:
+	return value;
+
       case NODE_DSTR:
-	break;
+	if (shareable == shareable_literal) {
+	    value = NEW_CALL(value, idUMinus, 0, loc);
+	}
+	return value;
 
       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;
+	return value;
 
       case NODE_ZLIST:
+	lit = rb_ary_new();
+	OBJ_FREEZE_RAW(lit);
 	nd_set_type(value, NODE_LIT);
-	RB_OBJ_WRITE(p->ast, &value->nd_lit, rb_ary_new());
-	break;
+	RB_OBJ_WRITE(p->ast, &value->nd_lit, lit);
+	return value;
 
       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_next(elt))) {
-		if (lit) {
+	    if (elt) {
+		elt = shareable_literal_constant_next(elt);
+		if (elt) {
+		    n->nd_head = elt;
+		}
+		else if (RTEST(lit)) {
 		    rb_ary_clear(lit);
 		    lit = Qfalse;
 		}
 	    }
-	    if (lit) {
+	    if (RTEST(lit)) {
 		VALUE e = shareable_literal_value(elt);
 		if (e != Qundef) {
 		    rb_ary_push(lit, e);
 		}
 		else {
 		    rb_ary_clear(lit);
-		    lit = Qfalse;
+		    lit = Qnil;	/* make shareable at runtime */
 		}
 	    }
 	}
-	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:
@@ -11102,14 +11159,27 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable, https://github.com/ruby/ruby/blob/trunk/parse.y#L11159
 	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_next(key))) ||
-		(val && !(val = shareable_literal_constant_next(val)))) {
-		if (lit) {
+	    if (key) {
+		key = shareable_literal_constant_next(key);
+		if (key) {
+		    n->nd_head = key;
+		}
+		else if (RTEST(lit)) {
 		    rb_hash_clear(lit);
 		    lit = Qfalse;
 		}
 	    }
-	    if (lit) {
+	    if (val) {
+		val = shareable_literal_constant_next(val);
+		if (val) {
+		    n->nd_next->nd_head = val;
+		}
+		else if (RTEST(lit)) {
+		    rb_hash_clear(lit);
+		    lit = Qfalse;
+		}
+	    }
+	    if (RTEST(lit)) {
 		VALUE k = shareable_literal_value(key);
 		VALUE v = shareable_literal_value(val);
 		if (k != Qundef && v != Qundef) {
@@ -11117,26 +11187,39 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable, https://github.com/ruby/ruby/blob/trunk/parse.y#L11187
 		}
 		else {
 		    rb_hash_clear(lit);
-		    lit = Qfalse;
+		    lit = Qnil;	/* make shareable at runtime */
 		}
 	    }
 	}
-	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 && level > 0)
-	    yyerror1(loc, "unshareable expression");
+	if (shareable == shareable_literal &&
+	    (SHAREABLE_BARE_EXPRESSION || level > 0)) {
+	    return ensure_shareable_node(p, dest, value, loc);
+	}
 	return 0;
     }
+
+    /* Array or Hash */
+    if (!lit) return 0;
+    if (NIL_P(lit)) {
+	// if shareable_literal, all elements should have been ensured
+	// as shareable
+	value = make_shareable_node(p, value, loc);
+    }
+    else {
+	nd_set_type(value, NODE_LIT);
+	RB_OBJ_WRITE(p->ast, &value->nd_lit, rb_ractor_make_shareable(lit));
+    }
+
     return value;
 # undef shareable_literal_constant_next
 }
 
 static NODE *
-shareable_constant_value(struct parser_params *p, NODE *value, enum shareability shareable, const YYLTYPE *loc)
+shareable_constant_value(struct parser_params *p, enum shareability shareable,
+			 NODE *lhs, NODE *value, const YYLTYPE *loc)
 {
     if (!value) return 0;
     switch (shareable) {
@@ -11144,18 +11227,24 @@ shareable_constant_value(struct parser_params *p, NODE *value, enum shareability https://github.com/ruby/ruby/blob/trunk/parse.y#L11227
 	return value;
 
       case shareable_literal:
+	{
+	    NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
+	    if (lit) return lit;
+	    return value;
+	}
+	break;
+
       case shareable_everything:
 	{
-	    NODE *lit = shareable_literal_constant(p, shareable, value, loc, 0);
+	    NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
 	    if (lit) return lit;
+	    return make_shareable_node(p, value, loc);
 	}
 	break;
 
       default:
 	UNREACHABLE_RETURN(0);
     }
-
-    return shareable_literal_node(p, value, loc);
 }
 
 static NODE *
@@ -11165,7 +11254,7 @@ node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ct https://github.com/ruby/ruby/blob/trunk/parse.y#L11254
 
     switch (nd_type(lhs)) {
       case NODE_CDECL:
-	rhs = shareable_constant_value(p, rhs, ctxt.shareable_constant_value, loc);
+	rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
 	/* fallthru */
 
       case NODE_GASGN:
@@ -12110,7 +12199,7 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c https://github.com/ruby/ruby/blob/trunk/parse.y#L12199
 	    }
 	}
 	if (op == tOROP) {
-	    rhs = shareable_constant_value(p, rhs, shareable, &rhs->nd_loc);
+	    rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
 	    lhs->nd_value = rhs;
 	    nd_set_loc(lhs, loc);
 	    asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
@@ -12125,7 +12214,7 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c https://github.com/ruby/ruby/blob/trunk/parse.y#L12214
 	}
 	else if (op == tANDOP) {
 	    if (shareable) {
-		rhs = shareable_constant_value(p, rhs, shareable, &rhs->nd_loc);
+		rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
 	    }
 	    lhs->nd_value = rhs;
 	    nd_set_loc(lhs, loc);
@@ -12135,7 +12224,7 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c https://github.com/ruby/ruby/blob/trunk/parse.y#L12224
 	    asgn = lhs;
 	    rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
 	    if (shareable) {
-		rhs = shareable_constant_value(p, rhs, shareable, &rhs->nd_loc);
+		rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
 	    }
 	    asgn->nd_value = rhs;
 	    nd_set_loc(asgn, loc);
@@ -12182,7 +12271,7 @@ new_const_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct https://github.com/ruby/ruby/blob/trunk/parse.y#L12271
     NODE *asgn;
 
     if (lhs) {
-	rhs = shareable_constant_value(p, rhs, ctxt.shareable_constant_value, loc);
+	rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]