ruby-changes:67164
From: Kazuki <ko1@a...>
Date: Sun, 15 Aug 2021 10:34:54 +0900 (JST)
Subject: [ruby-changes:67164] 4568ba0711 (master): Show verbose error messages when single pattern match fails
https://git.ruby-lang.org/ruby.git/commit/?id=4568ba0711 From 4568ba071107a139b9f02fc17aa12f998181abf1 Mon Sep 17 00:00:00 2001 From: Kazuki Tsujimoto <kazuki@c...> Date: Sun, 15 Aug 2021 09:38:24 +0900 Subject: Show verbose error messages when single pattern match fails [0] => [0, *, a] #=> [0] length mismatch (given 1, expected 2+) (NoMatchingPatternError) Ignore test failures of typeprof caused by this change for now. --- .github/workflows/ubuntu.yml | 2 +- compile.c | 456 +++++++++++++++++++++++++++++-------- defs/id.def | 1 + error.c | 75 +++++- include/ruby/internal/globals.h | 1 + test/ruby/test_pattern_matching.rb | 127 +++++++++++ vm.c | 7 + 7 files changed, 572 insertions(+), 97 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index e148b76..f3ad645 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -59,7 +59,7 @@ jobs: https://github.com/ruby/ruby/blob/trunk/.github/workflows/ubuntu.yml#L59 timeout-minutes: 30 env: RUBY_TESTOPTS: "-q --tty=no" - TEST_BUNDLED_GEMS_ALLOW_FAILURES: "" + TEST_BUNDLED_GEMS_ALLOW_FAILURES: "typeprof" - uses: k0kubun/action-slack@v... with: payload: | diff --git a/compile.c b/compile.c index 6695a02..d73a42a 100644 --- a/compile.c +++ b/compile.c @@ -5939,12 +5939,22 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no https://github.com/ruby/ruby/blob/trunk/compile.c#L5939 return COMPILE_OK; } -static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos); +static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache); -static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, int deconstructed_pos); +static int iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index); +static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache); +static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index); +static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index); +static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index); + +#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0 +#define CASE3_BI_OFFSET_ERROR_STRING 1 +#define CASE3_BI_OFFSET_KEY_ERROR_P 2 +#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3 +#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4 static int -iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos) +iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache) { const int line = nd_line(node); const NODE *line_node = node; @@ -6022,31 +6032,32 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6032 if (use_rest_num) { ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */ ADD_INSN(ret, line_node, swap); - if (deconstructed_pos) { - deconstructed_pos++; + if (base_index) { + base_index++; } } - if (node->nd_pconst) { - ADD_INSN(ret, line_node, dup); - CHECK(COMPILE(ret, "constant", node->nd_pconst)); - ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); - ADD_INSNL(ret, line_node, branchunless, match_failed); - } + CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index)); - CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos)); + CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache)); ADD_INSN(ret, line_node, dup); ADD_SEND(ret, line_node, idLength, INT2FIX(0)); ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc)); - ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); + ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1) + if (in_single_pattern) { + CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, + apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") : + rb_fstring_lit("%p length mismatch (given %p, expected %p)"), + INT2FIX(min_argc), base_index + 1 /* (1) */)); + } ADD_INSNL(ret, line_node, branchunless, match_failed); for (i = 0; i < pre_args_num; i++) { ADD_INSN(ret, line_node, dup); ADD_INSN1(ret, line_node, putobject, INT2FIX(i)); - ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); - CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE)); + ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2) + CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false)); args = args->nd_next; } @@ -6059,9 +6070,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6070 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc)); ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); ADD_INSN1(ret, line_node, setn, INT2FIX(4)); - ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); + ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3) - CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_alt_pattern, FALSE)); + CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false)); } else { if (post_args_num > 0) { @@ -6083,8 +6094,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6094 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); ADD_SEND(ret, line_node, idPLUS, INT2FIX(1)); - ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); - CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE)); + ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4) + CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false)); args = args->nd_next; } @@ -6173,19 +6184,17 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6184 deconstruct = NEW_LABEL(line); deconstructed = NEW_LABEL(line); - if (node->nd_pconst) { - ADD_INSN(ret, line_node, dup); - CHECK(COMPILE(ret, "constant", node->nd_pconst)); - ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); - ADD_INSNL(ret, line_node, branchunless, match_failed); - } + CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index)); - CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos)); + CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache)); ADD_INSN(ret, line_node, dup); ADD_SEND(ret, line_node, idLength, INT2FIX(0)); ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num)); - ADD_SEND(ret, line_node, idGE, INT2FIX(1)); + ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1) + if (in_single_pattern) { + CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num), base_index + 1 /* (1) */)); + } ADD_INSNL(ret, line_node, branchunless, match_failed); { @@ -6196,13 +6205,13 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6205 int j; ADD_INSN(ret, line_node, dup); /* allocate stack for len */ - ADD_SEND(ret, line_node, idLength, INT2FIX(0)); + ADD_SEND(re (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/