diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb index 81b1b574de..1a29ee476c 100644 --- a/lib/error_highlight/base.rb +++ b/lib/error_highlight/base.rb @@ -62,7 +62,7 @@ module ErrorHighlight # includes "prism" when the ISEQ was compiled with the prism compiler. # In this case, we'll try to parse again with prism instead. raise unless error.message.include?("prism") - prism_find(loc, **opts) + prism_find(loc) end Spotter.new(node, **opts).spot @@ -82,66 +82,16 @@ module ErrorHighlight end # Accepts a Thread::Backtrace::Location object and returns a Prism::Node - # corresponding to the location in the source code. - def self.prism_find(loc, point_type: :name, name: nil) + # corresponding to the backtrace location in the source code. + def self.prism_find(location) require "prism" return nil if Prism::VERSION < "0.29.0" - path = loc.absolute_path - return unless path + absolute_path = location.absolute_path + return unless absolute_path - lineno = loc.lineno - column = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc) - tunnel = Prism.parse_file(path).value.tunnel(lineno, column) - - # Prism provides the Prism::Node#tunnel API to find all of the nodes that - # correspond to the given line and column in the source code, with the first - # node in the list being the top-most node and the last node in the list - # being the bottom-most node. - tunnel.each_with_index.reverse_each.find do |part, index| - case part - when Prism::CallNode, Prism::CallOperatorWriteNode, Prism::IndexOperatorWriteNode, Prism::LocalVariableOperatorWriteNode - # If we find any of these nodes, we can stop searching as these are the - # nodes that triggered the exceptions. - break part - when Prism::ConstantReadNode, Prism::ConstantPathNode - if index != 0 && tunnel[index - 1].is_a?(Prism::ConstantPathOperatorWriteNode) - # If we're inside of a constant path operator write node, then this - # constant path may be highlighting a couple of different kinds of - # parts. - if part.name == name - # Explicitly turn off Foo::Bar += 1 where Foo and Bar are on - # different lines because error highlight expects this to not work. - break nil if part.delimiter_loc.end_line != part.name_loc.start_line - - # Otherwise, because we have matched the name we can return this - # part. - break part - end - - # If we haven't matched the name, it's the operator that we're looking - # for, and we can return the parent node here. - break tunnel[index - 1] - elsif part.name == name - # If we have matched the name of the constant, then we can return this - # inner node as the node that triggered the exception. - break part - else - # If we are at the beginning of the tunnel or we are at the beginning - # of a constant lookup chain, then we will return this node. - break part if index == 0 || !tunnel[index - 1].is_a?(Prism::ConstantPathNode) - end - when Prism::LocalVariableReadNode, Prism::ParenthesesNode - # If we find any of these nodes, we want to continue searching up the - # tree because these nodes cannot trigger the exceptions. - false - else - # If we find a different kind of node that we haven't already handled, - # we don't know how to handle it so we'll stop searching and assume this - # is not an exception we can decorate. - break nil - end - end + node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location) + Prism.parse_file(absolute_path).value.breadth_first_search { |node| node.node_id == node_id } end private_class_method :prism_find @@ -178,31 +128,49 @@ module ErrorHighlight def spot return nil unless @node - if OPT_GETCONSTANT_PATH && @node.type == :COLON2 + if OPT_GETCONSTANT_PATH # In Ruby 3.2 or later, a nested constant access (like `Foo::Bar::Baz`) # is compiled to one instruction (opt_getconstant_path). # @node points to the node of the whole `Foo::Bar::Baz` even if `Foo` # or `Foo::Bar` causes NameError. # So we try to spot the sub-node that causes the NameError by using # `NameError#name`. - subnodes = [] - node = @node - while node.type == :COLON2 - node2, const = node.children - subnodes << node if const == @name - node = node2 - end - if node.type == :CONST || node.type == :COLON3 - if node.children.first == @name + case @node.type + when :COLON2 + subnodes = [] + node = @node + while node.type == :COLON2 + node2, const = node.children + subnodes << node if const == @name + node = node2 + end + if node.type == :CONST || node.type == :COLON3 + if node.children.first == @name + subnodes << node + end + + # If we found only one sub-node whose name is equal to @name, use it + return nil if subnodes.size != 1 + @node = subnodes.first + else + # Do nothing; opt_getconstant_path is used only when the const base is + # NODE_CONST (`Foo`) or NODE_COLON3 (`::Foo`) + end + when :constant_path_node + subnodes = [] + node = @node + + begin + subnodes << node if node.name == @name + end while (node = node.parent).is_a?(Prism::ConstantPathNode) + + if node.is_a?(Prism::ConstantReadNode) && node.name == @name subnodes << node end # If we found only one sub-node whose name is equal to @name, use it return nil if subnodes.size != 1 @node = subnodes.first - else - # Do nothing; opt_getconstant_path is used only when the const base is - # NODE_CONST (`Foo`) or NODE_COLON3 (`::Foo`) end end @@ -847,7 +815,11 @@ module ErrorHighlight # Foo::Bar += 1 # ^^^^^^^^ def prism_spot_constant_path_operator_write - prism_location(@node.binary_operator_loc.chop) + if @name == (target = @node.target).name + prism_location(target.delimiter_loc.join(target.name_loc)) + else + prism_location(@node.binary_operator_loc.chop) + end end end diff --git a/prism/util/pm_newline_list.c b/prism/util/pm_newline_list.c index ce07ce8c8e..8331618f54 100644 --- a/prism/util/pm_newline_list.c +++ b/prism/util/pm_newline_list.c @@ -54,6 +54,35 @@ pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) { return true; } +/** + * Returns the line of the given offset. If the offset is not in the list, the + * line of the closest offset less than the given offset is returned. + */ +int32_t +pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) { + assert(cursor >= list->start); + size_t offset = (size_t) (cursor - list->start); + + size_t left = 0; + size_t right = list->size - 1; + + while (left <= right) { + size_t mid = left + (right - left) / 2; + + if (list->offsets[mid] == offset) { + return ((int32_t) mid) + start_line; + } + + if (list->offsets[mid] < offset) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return ((int32_t) left) + start_line - 1; +} + /** * Returns the line and column of the given offset. If the offset is not in the * list, the line and column of the closest offset less than the given offset diff --git a/prism/util/pm_newline_list.h b/prism/util/pm_newline_list.h index 7ae9b6b3da..406abe8ba5 100644 --- a/prism/util/pm_newline_list.h +++ b/prism/util/pm_newline_list.h @@ -80,6 +80,17 @@ pm_newline_list_clear(pm_newline_list_t *list); */ bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor); +/** + * Returns the line of the given offset. If the offset is not in the list, the + * line of the closest offset less than the given offset is returned. + * + * @param list The list to search. + * @param cursor A pointer to the offset to search for. + * @param start_line The line to start counting from. + * @return The line of the given offset. + */ +int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line); + /** * Returns the line and column of the given offset. If the offset is not in the * list, the line and column of the closest offset less than the given offset diff --git a/prism_compile.c b/prism_compile.c index 467da684f1..d074890fc3 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1,7 +1,20 @@ #include "prism.h" +/** + * This compiler defines its own concept of the location of a node. We do this + * because we want to pair line information with node identifier so that we can + * have reproducable parses. + */ +typedef struct { + /** This is the line number of a node. */ + int32_t line; + + /** This is a unique identifier for the node. */ + uint32_t node_id; +} pm_node_location_t; + /******************************************************************************/ -/* These macros operate on pm_line_column_t structs as opposed to NODE*s. */ +/* These macros operate on pm_node_location_t structs as opposed to NODE*s. */ /******************************************************************************/ #define PUSH_ADJUST(seq, location, label) \ @@ -11,16 +24,16 @@ ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1)) #define PUSH_INSN(seq, location, insn) \ - ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).column, BIN(insn), 0)) + ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 0)) #define PUSH_INSN1(seq, location, insn, op1) \ - ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).column, BIN(insn), 1, (VALUE)(op1))) + ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 1, (VALUE)(op1))) #define PUSH_INSN2(seq, location, insn, op1, op2) \ - ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).column, BIN(insn), 2, (VALUE)(op1), (VALUE)(op2))) + ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 2, (VALUE)(op1), (VALUE)(op2))) #define PUSH_INSN3(seq, location, insn, op1, op2, op3) \ - ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).column, BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3))) + ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3))) #define PUSH_INSNL(seq, location, insn, label) \ (PUSH_INSN1(seq, location, insn, label), LABEL_REF(label)) @@ -29,7 +42,7 @@ ADD_ELEM((seq), (LINK_ELEMENT *) (label)) #define PUSH_SEND_R(seq, location, id, argc, block, flag, keywords) \ - ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (int) (location).line, (int) (location).column, (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords))) + ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (int) (location).line, (int) (location).node_id, (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords))) #define PUSH_SEND(seq, location, id, argc) \ PUSH_SEND_R((seq), location, (id), (argc), NULL, (VALUE)INT2FIX(0), NULL) @@ -68,34 +81,34 @@ /******************************************************************************/ static void -pm_iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line_no, int column, int idx, int level) +pm_iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node_id, int idx, int level) { if (iseq_local_block_param_p(iseq, idx, level)) { - ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line_no, column, BIN(getblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); + ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(getblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); } else { - ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line_no, column, BIN(getlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); + ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(getlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); } if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse); } static void -pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line_no, int column, int idx, int level) +pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node_id, int idx, int level) { if (iseq_local_block_param_p(iseq, idx, level)) { - ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line_no, column, BIN(setblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); + ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(setblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); } else { - ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line_no, column, BIN(setlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); + ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(setlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level))); } if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue); } #define PUSH_GETLOCAL(seq, location, idx, level) \ - pm_iseq_add_getlocal(iseq, (seq), (int) (location).line, (int) (location).column, (idx), (level)) + pm_iseq_add_getlocal(iseq, (seq), (int) (location).line, (int) (location).node_id, (idx), (level)) #define PUSH_SETLOCAL(seq, location, idx, level) \ - pm_iseq_add_setlocal(iseq, (seq), (int) (location).line, (int) (location).column, (idx), (level)) + pm_iseq_add_setlocal(iseq, (seq), (int) (location).line, (int) (location).node_id, (idx), (level)) /******************************************************************************/ /* These are helper macros for the compiler. */ @@ -131,6 +144,15 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line_no, int c #define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG)) #define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG)) +#define PM_NODE_START_LOCATION(parser, node) \ + ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id }) + +#define PM_NODE_END_LOCATION(parser, node) \ + ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.end, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id }) + +#define PM_LOCATION_START_LOCATION(parser, location, id) \ + ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, (location)->start, (parser)->start_line), .node_id = id }) + #define PM_NODE_START_LINE_COLUMN(parser, node) \ pm_newline_list_line_column(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line) @@ -143,12 +165,12 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line_no, int c static int pm_node_line_number(const pm_parser_t *parser, const pm_node_t *node) { - return (int) PM_NODE_START_LINE_COLUMN(parser, node).line; + return (int) pm_newline_list_line(&parser->newline_list, node->location.start, parser->start_line); } static int pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location) { - return (int) PM_LOCATION_START_LINE_COLUMN(parser, location).line; + return (int) pm_newline_list_line(&parser->newline_list, location->start, parser->start_line); } /** @@ -543,7 +565,7 @@ parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node); static int -pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding) +pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding) { int stack_size = 0; size_t parts_size = parts->size; @@ -551,7 +573,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const if (parts_size > 0) { VALUE current_string = Qnil; - pm_line_column_t current_location = *node_location; + pm_node_location_t current_location = *node_location; for (size_t index = 0; index < parts_size; index++) { const pm_node_t *part = parts->nodes[index]; @@ -572,7 +594,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const } else { current_string = string_value; - if (index != 0) current_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, part); + if (index != 0) current_location = PM_NODE_END_LOCATION(scope_node->parser, part); } } else { @@ -599,7 +621,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const } else { current_string = string_value; - current_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, part); + current_location = PM_NODE_START_LOCATION(scope_node->parser, part); } } else { @@ -627,7 +649,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const PUSH_INSN1(ret, current_location, putobject, rb_fstring(current_string)); PM_COMPILE_NOT_POPPED(part); - const pm_line_column_t current_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, part); + const pm_node_location_t current_location = PM_NODE_START_LOCATION(scope_node->parser, part); PUSH_INSN(ret, current_location, dup); PUSH_INSN1(ret, current_location, objtostring, new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE, NULL, FALSE)); PUSH_INSN(ret, current_location, anytostring); @@ -660,7 +682,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const } static void -pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *parts, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node); rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding; @@ -835,7 +857,7 @@ pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_no static void pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, cond); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond); DECL_ANCHOR(seq); INIT_ANCHOR(seq); @@ -865,7 +887,7 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB static void pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .column = -1 }; + const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 }; if (PM_NODE_TYPE_P(node, PM_INTEGER_NODE)) { PM_COMPILE_NOT_POPPED(node); @@ -881,7 +903,7 @@ pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR * static void pm_compile_flip_flop(const pm_flip_flop_node_t *flip_flop_node, LABEL *else_label, LABEL *then_label, rb_iseq_t *iseq, const int lineno, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .column = -1 }; + const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 }; LABEL *lend = NEW_LABEL(location.line); int again = !(flip_flop_node->base.flags & PM_RANGE_FLAGS_EXCLUDE_END); @@ -920,12 +942,12 @@ pm_compile_flip_flop(const pm_flip_flop_node_t *flip_flop_node, LABEL *else_labe PUSH_INSNL(ret, location, jump, then_label); } -static void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition); +static void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition); static void pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, cond); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond); again: switch (PM_NODE_TYPE(cond)) { @@ -980,9 +1002,9 @@ again: * Compile an if or unless node. */ static void -pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_type_t type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *consequent, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_node_type_t type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *consequent, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *line_column; + const pm_node_location_t location = *node_location; LABEL *then_label = NEW_LABEL(location.line); LABEL *else_label = NEW_LABEL(location.line); LABEL *end_label = NULL; @@ -1084,9 +1106,9 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_ * Compile a while or until loop. */ static void -pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_flags_t flags, enum pm_node_type type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_loop(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_node_flags_t flags, enum pm_node_type type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *line_column; + const pm_node_location_t location = *node_location; LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label; LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label; @@ -1219,7 +1241,7 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i } static int -pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { if (PM_NODE_TYPE_P(node, PM_CONSTANT_PATH_NODE)) { const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent; @@ -1247,9 +1269,9 @@ pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_colu * method calls that are followed by a ||= or &&= operator. */ static void -pm_compile_call_and_or_write_node(rb_iseq_t *iseq, bool and_node, const pm_node_t *receiver, const pm_node_t *value, pm_constant_id_t write_name, pm_constant_id_t read_name, bool safe_nav, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_call_and_or_write_node(rb_iseq_t *iseq, bool and_node, const pm_node_t *receiver, const pm_node_t *value, pm_constant_id_t write_name, pm_constant_id_t read_name, bool safe_nav, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; LABEL *lfin = NEW_LABEL(location.line); LABEL *lcfin = NEW_LABEL(location.line); LABEL *lskip = NULL; @@ -1305,7 +1327,7 @@ pm_compile_call_and_or_write_node(rb_iseq_t *iseq, bool and_node, const pm_node_ static void pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); // If this element is not popped, then we need to create the hash on the // stack. Neighboring plain assoc nodes should be grouped together (either @@ -1394,9 +1416,9 @@ pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l // This is details. Users should call pm_setup_args() instead. static int -pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, const bool has_regular_blockarg, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_line_column_t *node_location) +pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, const bool has_regular_blockarg, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_node_location_t *node_location) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; int orig_argc = 0; bool has_splat = false; @@ -1655,7 +1677,7 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b // Compile the argument parts of a call static int -pm_setup_args(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_line_column_t *node_location) +pm_setup_args(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_node_location_t *node_location) { if (block && PM_NODE_TYPE_P(block, PM_BLOCK_ARGUMENT_NODE)) { // We compile the `&block_arg` expression first and stitch it later @@ -1701,9 +1723,9 @@ pm_setup_args(const pm_arguments_node_t *arguments_node, const pm_node_t *block, * and then calling the []= method with the result of the operator method. */ static void -pm_compile_index_operator_write_node(rb_iseq_t *iseq, const pm_index_operator_write_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_index_operator_write_node(rb_iseq_t *iseq, const pm_index_operator_write_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; if (!popped) PUSH_INSN(ret, location, putnil); PM_COMPILE_NOT_POPPED(node->receiver); @@ -1818,9 +1840,9 @@ pm_compile_index_operator_write_node(rb_iseq_t *iseq, const pm_index_operator_wr * []= method. */ static void -pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_t *receiver, const pm_arguments_node_t *arguments, const pm_node_t *block, const pm_node_t *value, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_t *receiver, const pm_arguments_node_t *arguments, const pm_node_t *block, const pm_node_t *value, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; if (!popped) PUSH_INSN(ret, location, putnil); PM_COMPILE_NOT_POPPED(receiver); @@ -1961,7 +1983,7 @@ static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, cons static int pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -1991,7 +2013,7 @@ pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, c static int pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, VALUE length, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -2024,7 +2046,7 @@ pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, co static int pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); LABEL *match_succeeded_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); @@ -2072,7 +2094,7 @@ pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_ static int pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *deconstruct_label, LABEL *match_failed_label, LABEL *deconstructed_label, LABEL *type_error_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); if (use_deconstructed_cache) { PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE)); @@ -2124,7 +2146,7 @@ pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, con static int pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); PUSH_INSN(ret, location, dup); PM_COMPILE_NOT_POPPED(node); @@ -2147,7 +2169,7 @@ pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const static void pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *done_label, bool popped) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); LABEL *key_error_label = NEW_LABEL(location.line); LABEL *cleanup_label = NEW_LABEL(location.line); @@ -2196,7 +2218,7 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_n static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); switch (PM_NODE_TYPE(node)) { case PM_ARRAY_PATTERN_NODE: { @@ -3038,7 +3060,7 @@ pm_iseq_builtin_function_name(const pm_scope_node_t *scope_node, const pm_node_t // Compile Primitive.attr! :leaf, ... static int -pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_line_column_t *node_location) +pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location) { if (arguments == NULL) { COMPILE_ERROR(iseq, node_location->line, "attr!: no argument"); @@ -3074,7 +3096,7 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons } static int -pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_line_column_t *node_location, int popped) +pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location, int popped) { if (arguments == NULL) { COMPILE_ERROR(iseq, node_location->line, "arg!: no argument"); @@ -3104,7 +3126,7 @@ pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_n } static int -pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_line_column_t *node_location) +pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_node_location_t *node_location) { const pm_node_t *ast_node = scope_node->ast_node; if (!PM_NODE_TYPE_P(ast_node, PM_DEF_NODE)) { @@ -3169,7 +3191,7 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope } static int -pm_compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_line_column_t *node_location, int popped, const rb_iseq_t *parent_block, const char *builtin_func) +pm_compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_node_location_t *node_location, int popped, const rb_iseq_t *parent_block, const char *builtin_func) { const pm_arguments_node_t *arguments = call_node->arguments; @@ -3270,14 +3292,14 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c const pm_location_t *message_loc = &call_node->message_loc; if (message_loc->start == NULL) message_loc = &call_node->base.location; - const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, message_loc); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, call_node->base.node_id); LABEL *else_label = NEW_LABEL(location.line); LABEL *end_label = NEW_LABEL(location.line); LABEL *retry_end_l = NEW_LABEL(location.line); VALUE branches = Qfalse; rb_code_location_t code_location = { 0 }; - int node_id = location.column; + int node_id = location.node_id; if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { if (PM_BRANCH_COVERAGE_P(iseq)) { @@ -3387,11 +3409,11 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c } static void -pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver) +pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver) { // in_condition is the same as compile.c's needstr enum defined_type dtype = DEFINED_NOT_DEFINED; - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; switch (PM_NODE_TYPE(node)) { case PM_ARGUMENTS_NODE: { @@ -3739,7 +3761,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_c } static void -pm_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver) +pm_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver) { LINK_ELEMENT *lcur = ret->last; pm_compile_defined_expr0(iseq, node, node_location, ret, popped, scope_node, in_condition, lfinish, false); @@ -3770,7 +3792,7 @@ pm_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t * } static void -pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition) +pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition) { LABEL *lfinish[3]; LINK_ELEMENT *last = ret->last; @@ -3784,7 +3806,7 @@ pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_co } if (lfinish[1]) { - ELEM_INSERT_NEXT(last, &new_insn_body(iseq, node_location->line, node_location->column, BIN(putnil), 0)->link); + ELEM_INSERT_NEXT(last, &new_insn_body(iseq, node_location->line, node_location->node_id, BIN(putnil), 0)->link); PUSH_INSN(ret, *node_location, swap); if (lfinish[2]) PUSH_LABEL(ret, lfinish[2]); @@ -3952,7 +3974,7 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl static inline void pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, node->name, 0); PUSH_SETLOCAL(ret, location, index.index, index.level); } @@ -3968,7 +3990,7 @@ pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter static void pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); bool has_rest = (node->rest && PM_NODE_TYPE_P(node->rest, PM_SPLAT_NODE) && (((const pm_splat_node_t *) node->rest)->expression) != NULL); bool has_rights = node->rights.size > 0; @@ -4165,7 +4187,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR static void pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); switch (PM_NODE_TYPE(node)) { case PM_LOCAL_VARIABLE_TARGET_NODE: { @@ -4396,7 +4418,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons static void pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); const pm_node_list_t *lefts; const pm_node_t *rest; const pm_node_list_t *rights; @@ -4479,7 +4501,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR static void pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); switch (PM_NODE_TYPE(node)) { case PM_LOCAL_VARIABLE_TARGET_NODE: { @@ -4567,7 +4589,7 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c } static void -pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { const pm_parser_t *parser = scope_node->parser; @@ -4618,11 +4640,11 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_line_co } static void -pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { const pm_parser_t *parser = scope_node->parser; const pm_statements_node_t *statements = cast->ensure_clause->statements; - const pm_line_column_t location = statements != NULL ? PM_NODE_START_LINE_COLUMN(parser, statements) : *node_location; + const pm_node_location_t location = statements != NULL ? PM_NODE_START_LOCATION(parser, statements) : *node_location; LABEL *estart = NEW_LABEL(location.line); LABEL *eend = NEW_LABEL(location.line); @@ -4741,9 +4763,9 @@ pm_opt_aset_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node) * of the current iseq. */ static void -pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node) +pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, name_loc); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, name_loc, node_id); if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { ISEQ_BODY(iseq)->ic_size++; @@ -4802,7 +4824,7 @@ pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node) static void pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const prefix, LINK_ANCHOR *const body, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); switch (PM_NODE_TYPE(node)) { case PM_CONSTANT_READ_NODE: { @@ -4964,12 +4986,12 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons { VALUE literal = pm_compile_shareable_constant_literal(iseq, node, scope_node); if (literal != Qundef) { - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); PUSH_INSN1(ret, location, putobject, literal); return; } - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); switch (PM_NODE_TYPE(node)) { case PM_ARRAY_NODE: { const pm_array_node_t *cast = (const pm_array_node_t *) node; @@ -5055,9 +5077,9 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons * not. */ static void -pm_compile_constant_write_node(rb_iseq_t *iseq, const pm_constant_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_write_node(rb_iseq_t *iseq, const pm_constant_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; ID name_id = pm_constant_id_lookup(scope_node, node->name); if (shareability != 0) { @@ -5077,14 +5099,14 @@ pm_compile_constant_write_node(rb_iseq_t *iseq, const pm_constant_write_node_t * * or not. */ static void -pm_compile_constant_and_write_node(rb_iseq_t *iseq, const pm_constant_and_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_and_write_node(rb_iseq_t *iseq, const pm_constant_and_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name)); LABEL *end_label = NEW_LABEL(location.line); - pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node); + pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node); if (!popped) PUSH_INSN(ret, location, dup); PUSH_INSNL(ret, location, branchunless, end_label); @@ -5108,9 +5130,9 @@ pm_compile_constant_and_write_node(rb_iseq_t *iseq, const pm_constant_and_write_ * not. */ static void -pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name)); LABEL *set_label = NEW_LABEL(location.line); @@ -5120,7 +5142,7 @@ pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_no PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST), name, Qtrue); PUSH_INSNL(ret, location, branchunless, set_label); - pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node); + pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node); if (!popped) PUSH_INSN(ret, location, dup); PUSH_INSNL(ret, location, branchif, end_label); @@ -5145,14 +5167,14 @@ pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_no * pragma or not. */ static void -pm_compile_constant_operator_write_node(rb_iseq_t *iseq, const pm_constant_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_operator_write_node(rb_iseq_t *iseq, const pm_constant_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name)); ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator); - pm_compile_constant_read(iseq, name, &node->name_loc, ret, scope_node); + pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node); if (shareability != 0) { pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true); @@ -5203,9 +5225,9 @@ pm_constant_path_path(const pm_constant_path_node_t *node, const pm_scope_node_t * or not. */ static void -pm_compile_constant_path_write_node(rb_iseq_t *iseq, const pm_constant_path_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_path_write_node(rb_iseq_t *iseq, const pm_constant_path_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; const pm_constant_path_node_t *target = node->target; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name)); @@ -5237,9 +5259,9 @@ pm_compile_constant_path_write_node(rb_iseq_t *iseq, const pm_constant_path_writ * pragma or not. */ static void -pm_compile_constant_path_and_write_node(rb_iseq_t *iseq, const pm_constant_path_and_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_path_and_write_node(rb_iseq_t *iseq, const pm_constant_path_and_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; const pm_constant_path_node_t *target = node->target; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name)); @@ -5288,9 +5310,9 @@ pm_compile_constant_path_and_write_node(rb_iseq_t *iseq, const pm_constant_path_ * pragma or not. */ static void -pm_compile_constant_path_or_write_node(rb_iseq_t *iseq, const pm_constant_path_or_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_path_or_write_node(rb_iseq_t *iseq, const pm_constant_path_or_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; const pm_constant_path_node_t *target = node->target; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name)); @@ -5345,9 +5367,9 @@ pm_compile_constant_path_or_write_node(rb_iseq_t *iseq, const pm_constant_path_o * ractor pragma or not. */ static void -pm_compile_constant_path_operator_write_node(rb_iseq_t *iseq, const pm_constant_path_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_line_column_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) +pm_compile_constant_path_operator_write_node(rb_iseq_t *iseq, const pm_constant_path_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { - const pm_line_column_t location = *node_location; + const pm_node_location_t location = *node_location; const pm_constant_path_node_t *target = node->target; ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator); @@ -5396,7 +5418,7 @@ static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { const pm_parser_t *parser = scope_node->parser; - const pm_line_column_t location = PM_NODE_START_LINE_COLUMN(parser, node); + const pm_node_location_t location = PM_NODE_START_LOCATION(parser, node); int lineno = (int) location.line; if (PM_NODE_TYPE_P(node, PM_RETURN_NODE) && PM_NODE_FLAG_P(node, PM_RETURN_NODE_FLAGS_REDUNDANT) && ((const pm_return_node_t *) node)->arguments == NULL) { @@ -5770,7 +5792,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const pm_location_t *message_loc = &cast->message_loc; if (message_loc->start == NULL) message_loc = &cast->base.location; - const pm_line_column_t location = PM_LOCATION_START_LINE_COLUMN(scope_node->parser, message_loc); + const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, cast->base.node_id); const char *builtin_func; if (UNLIKELY(iseq_has_builtin_function_table(iseq)) && (builtin_func = pm_iseq_builtin_function_name(scope_node, cast->receiver, method_id)) != NULL) { @@ -5981,7 +6003,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const pm_node_t *condition = conditions->nodes[condition_index]; if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) { - pm_line_column_t cond_location = PM_NODE_START_LINE_COLUMN(parser, condition); + pm_node_location_t cond_location = PM_NODE_START_LOCATION(parser, condition); PUSH_INSN(cond_seq, cond_location, putnil); pm_compile_node(iseq, condition, cond_seq, false, scope_node); PUSH_INSN1(cond_seq, cond_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY)); @@ -6060,7 +6082,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, // node instructions later. for (size_t clause_index = 0; clause_index < conditions->size; clause_index++) { const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index]; - pm_line_column_t clause_location = PM_NODE_START_LINE_COLUMN(parser, (const pm_node_t *) clause); + pm_node_location_t clause_location = PM_NODE_START_LOCATION(parser, (const pm_node_t *) clause); const pm_node_list_t *conditions = &clause->conditions; LABEL *label = NEW_LABEL(clause_location.line); @@ -6070,7 +6092,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, // jumps into the body if it matches. for (size_t condition_index = 0; condition_index < conditions->size; condition_index++) { const pm_node_t *condition = conditions->nodes[condition_index]; - const pm_line_column_t condition_location = PM_NODE_START_LINE_COLUMN(parser, condition); + const pm_node_location_t condition_location = PM_NODE_START_LOCATION(parser, condition); // If we haven't already abandoned the optimization, then // we're going to try to compile the condition into the @@ -6145,7 +6167,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, PUSH_LABEL(ret, else_label); if (cast->consequent != NULL) { - pm_line_column_t else_location = PM_NODE_START_LINE_COLUMN(parser, cast->consequent->statements != NULL ? ((const pm_node_t *) cast->consequent->statements) : ((const pm_node_t *) cast->consequent)); + pm_node_location_t else_location = PM_NODE_START_LOCATION(parser, cast->consequent->statements != NULL ? ((const pm_node_t *) cast->consequent->statements) : ((const pm_node_t *) cast->consequent)); PUSH_INSN(ret, else_location, pop); // Establish branch coverage for the else clause. @@ -6245,8 +6267,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, RUBY_ASSERT(PM_NODE_TYPE_P(condition, PM_IN_NODE)); const pm_in_node_t *in_node = (const pm_in_node_t *) condition; - const pm_line_column_t in_location = PM_NODE_START_LINE_COLUMN(parser, in_node); - const pm_line_column_t pattern_location = PM_NODE_START_LINE_COLUMN(parser, in_node->pattern); + const pm_node_location_t in_location = PM_NODE_START_LOCATION(parser, in_node); + const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(parser, in_node->pattern); if (branch_id) { PUSH_INSN(body_seq, in_location, putnil); @@ -6523,7 +6545,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node; VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name)); - pm_compile_constant_read(iseq, name, &cast->base.location, ret, scope_node); + pm_compile_constant_read(iseq, name, &cast->base.location, location.node_id, ret, scope_node); if (popped) PUSH_INSN(ret, location, pop); return; @@ -9020,7 +9042,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, case ISEQ_TYPE_BLOCK: { LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0); LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0); - const pm_line_column_t block_location = { .line = body->location.first_lineno, .column = -1 }; + const pm_node_location_t block_location = { .line = body->location.first_lineno, .node_id = -1 }; start->rescued = LABEL_RESCUE_BEG; end->rescued = LABEL_RESCUE_END; @@ -9077,7 +9099,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, break; } case ISEQ_TYPE_ENSURE: { - const pm_line_column_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LINE_COLUMN(scope_node->parser, scope_node->body) : location); + const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->parser, scope_node->body) : location); iseq_set_exception_local_table(iseq); if (scope_node->body != NULL) { @@ -9139,13 +9161,13 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, } if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE) || PM_NODE_TYPE_P(scope_node->ast_node, PM_MODULE_NODE)) { - const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, scope_node->ast_node); + const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->parser, scope_node->ast_node); ADD_TRACE(ret, RUBY_EVENT_END); ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line; } if (!PM_NODE_TYPE_P(scope_node->ast_node, PM_ENSURE_NODE)) { - const pm_line_column_t location = { .line = ISEQ_COMPILE_DATA(iseq)->last_line, .column = -1 }; + const pm_node_location_t location = { .line = ISEQ_COMPILE_DATA(iseq)->last_line, .node_id = -1 }; PUSH_INSN(ret, location, leave); } diff --git a/test/error_highlight/test_error_highlight.rb b/test/error_highlight/test_error_highlight.rb index 9af530b69f..de4e46ad42 100644 --- a/test/error_highlight/test_error_highlight.rb +++ b/test/error_highlight/test_error_highlight.rb @@ -5,13 +5,6 @@ require "did_you_mean" require "tempfile" class ErrorHighlightTest < Test::Unit::TestCase - # We can't revisit instruction sequences to find node ids if the prism - # compiler was used instead of the parse.y compiler. In that case, we'll omit - # some tests. - def self.compiling_with_prism? - RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism - end - class DummyFormatter def self.message_for(corrections) "" @@ -876,27 +869,13 @@ uninitialized constant ErrorHighlightTest::NotDefined end end - if ErrorHighlight.const_get(:Spotter).const_get(:OPT_GETCONSTANT_PATH) && !compiling_with_prism? - def test_COLON2_5 - # Unfortunately, we cannot identify which `NotDefined` caused the NameError - assert_error_message(NameError, <<~END) do + def test_COLON2_5 + # Unfortunately, we cannot identify which `NotDefined` caused the NameError + assert_error_message(NameError, <<~END) do uninitialized constant ErrorHighlightTest::NotDefined - END + END - ErrorHighlightTest::NotDefined::NotDefined - end - end - else - def test_COLON2_5 - assert_error_message(NameError, <<~END) do -uninitialized constant ErrorHighlightTest::NotDefined - - ErrorHighlightTest::NotDefined::NotDefined - ^^^^^^^^^^^^ - END - - ErrorHighlightTest::NotDefined::NotDefined - end + ErrorHighlightTest::NotDefined::NotDefined end end @@ -1342,7 +1321,11 @@ undefined method `foo' for #{ NIL_RECV_MESSAGE } def test_spot_with_node omit unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location) - omit if ErrorHighlightTest.compiling_with_prism? + + # We can't revisit instruction sequences to find node ids if the prism + # compiler was used instead of the parse.y compiler. In that case, we'll + # omit some tests. + omit if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism begin raise_name_error