Fix negative index double wrapping and add a test (fix #2826)
I would like to fix #2826 by removing the code to make `path(last)` work. New feature should be added carefully not to change the behavior of this kind of core features. Currently, as mentioned in the manual clearly as `For arrays, negative indices and .[m:n] specifications should not be used.`, we disallow negative indices and array slicing. I added path validation to follow how the manual states.
**Describe the bug**
Negative indices should wrap only once, not twice.

**To Reproduce**
`jq -n '[0,1,2] | .[-5]'` produces `1`.

**Expected behavior**
Since the array in the reproduction example has length 3, `.[-5]` can be `.[3-5]`, but still out of index so should produce `null`.

**Environment (please complete the following information):**

- OS and Version: macOS (whatever)
- jq version: jq-1.7rc1-25-gf94a9d4

**Additional context**
Likely the regression of a6fe347322bfd57cab2d2612d8825b4ede765ac8.
Array indexing of negative indices wraps twice
diff --git a/docs/content/manual/manual.yml b/docs/content/manual/manual.yml
index 6382d8354a..e6edbc7ba0 100644
--- a/docs/content/manual/manual.yml
+++ b/docs/content/manual/manual.yml
@@ -1048,10 +1048,11 @@ sections:
       - title: "`pick(pathexps)`"
         body: |
 
-          Emit the projection of the input object or array defined by the specified
-          sequence of path expressions, such that if p is any one of these specifications,
-          then `(. | p)` will evaluate to the same value as `(. | pick(pathexps) | p)`.
-          For arrays, negative indices and .[m:n] specifications should not be used.
+          Emit the projection of the input object or array defined by the
+          specified sequence of path expressions, such that if `p` is any
+          one of these specifications, then `(. | p)` will evaluate to the
+          same value as `(. | pick(pathexps) | p)`. For arrays, negative
+          indices and `.[m:n]` specifications should not be used.
 
         examples:
           - program: 'pick(.a, .b.c, .x)'
diff --git a/jq.1.prebuilt b/jq.1.prebuilt
index f386b49ce8..162881c11b 100644
--- a/jq.1.prebuilt
+++ b/jq.1.prebuilt
@@ -1050,7 +1050,7 @@ jq \'map_values(\. // empty)\'
 .IP "" 0
 .
 .SS "pick(pathexps)"
-Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if p is any one of these specifications, then \fB(\. | p)\fR will evaluate to the same value as \fB(\. | pick(pathexps) | p)\fR\. For arrays, negative indices and \.[m:n] specifications should not be used\.
+Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if \fBp\fR is any one of these specifications, then \fB(\. | p)\fR will evaluate to the same value as \fB(\. | pick(pathexps) | p)\fR\. For arrays, negative indices and \fB\.[m:n]\fR specifications should not be used\.
 .
 .IP "" 4
 .
diff --git a/src/execute.c b/src/execute.c
index ae92c37317..367819e8a9 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -694,14 +694,6 @@ jv jq_next(jq_state *jq) {
         set_error(jq, jv_invalid_with_msg(msg));
         goto do_backtrack;
       }
-      // $array | .[-1]
-      if (jv_get_kind(k) == JV_KIND_NUMBER && jv_get_kind(t) == JV_KIND_ARRAY) {
-        int idx = jv_number_value(k);
-        if (idx < 0) {
-          jv_free(k);
-          k = jv_number(jv_array_length(jv_copy(t)) + idx);
-        }
-      }
       jv v = jv_get(t, jv_copy(k));
       if (jv_is_valid(v)) {
         path_append(jq, k, jv_copy(v));

diff --git a/tests/jq.test b/tests/jq.test
index de38e4def6..1dcb2542c8 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -248,9 +248,9 @@ null
 2
 3
 
-.[-2]
+[.[-4,-3,-2,-1,0,1,2,3]]
 [1,2,3]
-2
+[null,1,2,3,1,2,3,null]
 
 [range(0;10)]
 null
@@ -1052,9 +1052,9 @@ pick(first|first)
 [[10]]
 
 # negative indices in path expressions (since last/1 is .[-1])
-pick(last)
-[[10,20],30]
-[null,30]
+try pick(last) catch .
+[1,2]
+"Out of bounds negative array index"
 
 #
 # Assignment

{"tests/jqtest": {"run": "PASS", "test": "FAIL", "fix": "PASS"}}
{"test_options": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "regset": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "callback_each_match": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/utf8test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "names": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test_utf8": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "simple": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/base64test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "echo": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/mantest": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "testc": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test_syntax": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test_back": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "bug_fix": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "scan": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/onigtest": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/shtest": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "encode": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "callout": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "listcap": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/optionaltest": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "user_property": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "tests/manonigtest": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test_regset": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "testcu": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "count": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "syntax": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "sql": {"run": "PASS", "test": "PASS", "fix": "PASS"}}
{"tests/jqtest": {"run": "PASS", "test": "FAIL", "fix": "PASS"}}
{"passed_count": 29, "failed_count": 0, "skipped_count": 0, "passed_tests": ["regset", "callback_each_match", "names", "test_utf8", "testc", "test_syntax", "sql", "bug_fix", "scan", "tests/onigtest", "encode", "listcap", "tests/optionaltest", "tests/manonigtest", "test_regset", "testcu", "count", "syntax", "test_options", "tests/utf8test", "simple", "tests/base64test", "tests/mantest", "test_back", "tests/jqtest", "tests/shtest", "callout", "user_property", "echo"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 28, "failed_count": 1, "skipped_count": 0, "passed_tests": ["regset", "callback_each_match", "names", "test_utf8", "testc", "test_syntax", "sql", "bug_fix", "scan", "tests/onigtest", "encode", "listcap", "tests/optionaltest", "tests/manonigtest", "test_regset", "testcu", "count", "syntax", "test_options", "tests/utf8test", "simple", "tests/base64test", "tests/mantest", "test_back", "tests/shtest", "callout", "user_property", "echo"], "failed_tests": ["tests/jqtest"], "skipped_tests": []}
{"passed_count": 29, "failed_count": 0, "skipped_count": 0, "passed_tests": ["regset", "callback_each_match", "names", "test_utf8", "testc", "test_syntax", "sql", "bug_fix", "scan", "tests/onigtest", "encode", "listcap", "tests/optionaltest", "tests/manonigtest", "test_regset", "testcu", "count", "syntax", "test_options", "tests/utf8test", "simple", "tests/base64test", "tests/mantest", "test_back", "tests/jqtest", "tests/shtest", "callout", "user_property", "echo"], "failed_tests": [], "skipped_tests": []}