diff --git a/compile.c b/compile.c index bda18c1c42..7a58aa4e88 100644 --- a/compile.c +++ b/compile.c @@ -11298,6 +11298,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no rb_id2str(mid), ISEQ_TYPE_METHOD, line); +#ifdef USE_ISEQ_NODE_ID + // Store the DefNode's node_id in the method iseq location + ISEQ_BODY(method_iseq)->location.node_id = nd_node_id(node); +#endif + debugp_param("defn/iseq", rb_iseqw_new(method_iseq)); ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq); RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq); @@ -11314,6 +11319,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no rb_id2str(mid), ISEQ_TYPE_METHOD, line); +#ifdef USE_ISEQ_NODE_ID + // Store the DefNode's node_id in the singleton method iseq location + ISEQ_BODY(singleton_method_iseq)->location.node_id = nd_node_id(node); +#endif + debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq)); CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv)); ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq); diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb index 14e0ce5785..2294b9ede8 100644 --- a/lib/error_highlight/base.rb +++ b/lib/error_highlight/base.rb @@ -239,6 +239,14 @@ def spot when :OP_CDECL spot_op_cdecl + when :DEFN + raise NotImplementedError if @point_type != :name + spot_defn + + when :DEFS + raise NotImplementedError if @point_type != :name + spot_defs + when :call_node case @point_type when :name @@ -280,6 +288,14 @@ def spot when :constant_path_operator_write_node prism_spot_constant_path_operator_write + when :def_node + case @point_type + when :name + prism_spot_def_for_name + when :args + raise NotImplementedError + end + end if @snippet && @beg_column && @end_column && @beg_column < @end_column @@ -621,6 +637,30 @@ def spot_op_cdecl end end + # Example: + # def bar; end + # ^^^ + def spot_defn + mid, = @node.children + fetch_line(@node.first_lineno) + if @snippet.match(/\Gdef\s+(#{ Regexp.quote(mid) }\b)/, @node.first_column) + @beg_column = $~.begin(1) + @end_column = $~.end(1) + end + end + + # Example: + # def Foo.bar; end + # ^^^^ + def spot_defs + nd_recv, mid, = @node.children + fetch_line(nd_recv.last_lineno) + if @snippet.match(/\G\s*(\.\s*#{ Regexp.quote(mid) }\b)/, nd_recv.last_column) + @beg_column = $~.begin(1) + @end_column = $~.end(1) + end + end + def fetch_line(lineno) @beg_lineno = @end_lineno = lineno @snippet = @fetch[lineno] @@ -826,6 +866,12 @@ def prism_spot_constant_path_operator_write prism_location(@node.binary_operator_loc.chop) end end + + def prism_spot_def_for_name + location = @node.name_loc + location = location.join(@node.operator_loc) if @node.operator_loc + prism_location(location) + end end private_constant :Spotter diff --git a/lib/error_highlight/core_ext.rb b/lib/error_highlight/core_ext.rb index b69093f74e..7d2b73d9ff 100644 --- a/lib/error_highlight/core_ext.rb +++ b/lib/error_highlight/core_ext.rb @@ -3,9 +3,23 @@ module ErrorHighlight module CoreExt private def generate_snippet - spot = ErrorHighlight.spot(self) - return "" unless spot - return ErrorHighlight.formatter.message_for(spot) + if ArgumentError === self && message =~ /\Awrong number of arguments/ + locs = self.backtrace_locations + return "" if locs.size < 2 + callee_loc, caller_loc = locs + callee_spot = ErrorHighlight.spot(self, backtrace_location: callee_loc, point_type: :name) + return "" unless callee_spot + caller_spot = ErrorHighlight.spot(self, backtrace_location: caller_loc, point_type: :name) + return "" unless caller_spot + "\n\n" + [["caller", caller_loc, caller_spot], ["callee", callee_loc, callee_spot]].map do |msg, loc, spot| + _, _, snippet, highlight = ErrorHighlight.formatter.message_for(spot).lines + " #{ loc.path }:#{ loc.lineno }: #{ msg }\n | #{ snippet } #{ highlight }" + end.join("\n") + else + spot = ErrorHighlight.spot(self) + return "" unless spot + return ErrorHighlight.formatter.message_for(spot) + end end if Exception.method_defined?(:detailed_message) diff --git a/prism_compile.c b/prism_compile.c index 2f5bb4ebe3..b09fda8bb5 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -9116,6 +9116,11 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, rb_iseq_t *method_iseq = NEW_ISEQ(&next_scope_node, rb_id2str(method_name), ISEQ_TYPE_METHOD, location.line); pm_scope_node_destroy(&next_scope_node); +#ifdef USE_ISEQ_NODE_ID + // Store the DefNode's node_id in the method iseq location for Prism + ISEQ_BODY(method_iseq)->location.node_id = (int)location.node_id; +#endif + if (cast->receiver) { PM_COMPILE_NOT_POPPED(cast->receiver); PUSH_INSN2(ret, location, definesmethod, ID2SYM(method_name), method_iseq); diff --git a/vm_backtrace.c b/vm_backtrace.c index 12e4b771e2..1df7c92f45 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -44,7 +44,10 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id) } if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno; #ifdef USE_ISEQ_NODE_ID - if (node_id) *node_id = -1; + if (node_id) { + // Use the node_id stored in the iseq location + *node_id = ISEQ_BODY(iseq)->location.node_id; + } #endif return 1; } @@ -400,7 +403,7 @@ location_path_m(VALUE self) static int location_node_id(rb_backtrace_location_t *loc) { - if (loc->iseq && loc->pc) { + if (loc->iseq) { return calc_node_id(loc->iseq, loc->pc); } return -1;