summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaldun Bayhantopcu <haldun@github.com>2024-02-01 08:09:56 +0100
committergit <svn-admin@ruby-lang.org>2024-02-01 16:48:09 +0000
commit67c5690a6d29e861fcb8522dc4213f9d26d3aab6 (patch)
tree52c282a733a26d57be236b34b63513355b9c3ac5
parentf36c61d27fcdc47d4aa34e8a3b52590aac08bb69 (diff)
[ruby/prism] Check literals for receiver
https://github.com/ruby/prism/commit/56441b08e7
-rw-r--r--prism/diagnostic.c1
-rw-r--r--prism/diagnostic.h1
-rw-r--r--prism/prism.c43
-rw-r--r--test/prism/errors_test.rb46
4 files changed, 91 insertions, 0 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
index bf89ca781a..815a2b2a6c 100644
--- a/prism/diagnostic.c
+++ b/prism/diagnostic.c
@@ -261,6 +261,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_RESCUE_TERM] = { "expected a closing delimiter for the `rescue` clause", PM_ERROR_LEVEL_FATAL },
[PM_ERR_RESCUE_VARIABLE] = { "expected an exception variable after `=>` in a rescue statement", PM_ERROR_LEVEL_FATAL },
[PM_ERR_RETURN_INVALID] = { "invalid `return` in a class or module body", PM_ERROR_LEVEL_FATAL },
+ [PM_ERR_SINGLETON_FOR_LITERALS] = { "cannot define singleton method for literals", PM_ERROR_LEVEL_FATAL },
[PM_ERR_STATEMENT_ALIAS] = { "unexpected an `alias` at a non-statement position", PM_ERROR_LEVEL_FATAL },
[PM_ERR_STATEMENT_POSTEXE_END] = { "unexpected an `END` at a non-statement position", PM_ERROR_LEVEL_FATAL },
[PM_ERR_STATEMENT_PREEXE_BEGIN] = { "unexpected a `BEGIN` at a non-statement position", PM_ERROR_LEVEL_FATAL },
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
index 33123262b5..8f09fb9099 100644
--- a/prism/diagnostic.h
+++ b/prism/diagnostic.h
@@ -259,6 +259,7 @@ typedef enum {
PM_ERR_RESCUE_TERM,
PM_ERR_RESCUE_VARIABLE,
PM_ERR_RETURN_INVALID,
+ PM_ERR_SINGLETON_FOR_LITERALS,
PM_ERR_STATEMENT_ALIAS,
PM_ERR_STATEMENT_POSTEXE_END,
PM_ERR_STATEMENT_PREEXE_BEGIN,
diff --git a/prism/prism.c b/prism/prism.c
index aaa0035104..2f54e9ee93 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -2744,6 +2744,45 @@ pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *targ
}
/**
+ * Check if the receiver of a `def` node is allowed.
+ */
+static void
+pm_check_def_receiver(pm_parser_t *parser, pm_node_t *receiver) {
+ switch (receiver->type) {
+ case PM_BEGIN_NODE: {
+ pm_begin_node_t *begin_node = (pm_begin_node_t *)receiver;
+ pm_check_def_receiver(parser, (pm_node_t *) begin_node->statements);
+ break;
+ }
+ case PM_PARENTHESES_NODE:
+ pm_check_def_receiver(parser, ((pm_parentheses_node_t *) receiver)->body);
+ break;
+ case PM_STATEMENTS_NODE: {
+ pm_statements_node_t *statements_node = (pm_statements_node_t *)receiver;
+ pm_check_def_receiver(parser, statements_node->body.nodes[statements_node->body.size - 1]);
+ break;
+ }
+ case PM_ARRAY_NODE:
+ case PM_FLOAT_NODE:
+ case PM_IMAGINARY_NODE:
+ case PM_INTEGER_NODE:
+ case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
+ case PM_INTERPOLATED_STRING_NODE:
+ case PM_INTERPOLATED_SYMBOL_NODE:
+ case PM_INTERPOLATED_X_STRING_NODE:
+ case PM_RATIONAL_NODE:
+ case PM_REGULAR_EXPRESSION_NODE:
+ case PM_SOURCE_ENCODING_NODE:
+ case PM_SOURCE_FILE_NODE:
+ case PM_SOURCE_LINE_NODE:
+ case PM_STRING_NODE:
+ case PM_SYMBOL_NODE:
+ case PM_X_STRING_NODE:
+ pm_parser_err_node(parser, receiver, PM_ERR_SINGLETON_FOR_LITERALS);
+ }
+}
+
+/**
* Allocate and initialize a new DefNode node.
*/
static pm_def_node_t *
@@ -2771,6 +2810,10 @@ pm_def_node_create(
end = end_keyword->end;
}
+ if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
+ pm_check_def_receiver(parser, receiver);
+ }
+
*node = (pm_def_node_t) {
{
.type = PM_DEF_NODE,
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 62e72ea16a..c65fff5167 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -2087,6 +2087,52 @@ module Prism
assert_errors expression(source), source, errors, compare_ripper: false
end
+ def test_singleton_method_for_literals
+ source = <<~'RUBY'
+ def (1).g; end
+ def ((a; 1)).foo; end
+ def ((return; 1)).bar; end
+ def (((1))).foo; end
+ def (__FILE__).foo; end
+ def (__ENCODING__).foo; end
+ def (__LINE__).foo; end
+ def ("foo").foo; end
+ def (3.14).foo; end
+ def (3.14i).foo; end
+ def (:foo).foo; end
+ def (:'foo').foo; end
+ def (:'f{o}').foo; end
+ def ('foo').foo; end
+ def ("foo").foo; end
+ def ("#{fo}o").foo; end
+ def (/foo/).foo; end
+ def (/f#{oo}/).foo; end
+ def ([1]).foo; end
+ RUBY
+ errors = [
+ ["cannot define singleton method for literals", 5..6],
+ ["cannot define singleton method for literals", 24..25],
+ ["cannot define singleton method for literals", 51..52],
+ ["cannot define singleton method for literals", 71..72],
+ ["cannot define singleton method for literals", 90..98],
+ ["cannot define singleton method for literals", 114..126],
+ ["cannot define singleton method for literals", 142..150],
+ ["cannot define singleton method for literals", 166..171],
+ ["cannot define singleton method for literals", 187..191],
+ ["cannot define singleton method for literals", 207..212],
+ ["cannot define singleton method for literals", 228..232],
+ ["cannot define singleton method for literals", 248..254],
+ ["cannot define singleton method for literals", 270..277],
+ ["cannot define singleton method for literals", 293..298],
+ ["cannot define singleton method for literals", 314..319],
+ ["cannot define singleton method for literals", 335..343],
+ ["cannot define singleton method for literals", 359..364],
+ ["cannot define singleton method for literals", 380..388],
+ ["cannot define singleton method for literals", 404..407]
+ ]
+ assert_errors expression(source), source, errors, compare_ripper: false
+ end
+
private
def assert_errors(expected, source, errors, compare_ripper: RUBY_ENGINE == "ruby")