[njs] Fixed operator "in" according to the specification.

Dmitry Volyntsev xeioex at nginx.com
Tue Nov 26 15:38:33 UTC 2019


details:   https://hg.nginx.org/njs/rev/a41681864650
branches:  
changeset: 1261:a41681864650
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Tue Nov 26 13:22:09 2019 +0300
description:
Fixed operator "in" according to the specification.

diffstat:

 src/njs_vmcode.c         |  35 +++++++++++++----------------------
 src/test/njs_unit_test.c |  25 ++++++++++++++++++++-----
 2 files changed, 33 insertions(+), 27 deletions(-)

diffs (103 lines):

diff -r e5917fbde8d2 -r a41681864650 src/njs_vmcode.c
--- a/src/njs_vmcode.c	Tue Nov 26 15:11:40 2019 +0300
+++ b/src/njs_vmcode.c	Tue Nov 26 13:22:09 2019 +0300
@@ -1268,11 +1268,20 @@ static njs_jump_off_t
 njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *value, njs_value_t *key)
 {
     njs_int_t             ret;
-    njs_bool_t            found;
-    njs_object_prop_t     *prop;
     njs_property_query_t  pq;
 
-    found = 0;
+    if (njs_slow_path(njs_is_primitive(value))) {
+        njs_type_error(vm, "property \"in\" on primitive %s type",
+                       njs_type_string(value->type));
+        return NJS_ERROR;
+    }
+
+    if (njs_slow_path(!njs_is_key(key))) {
+        ret = njs_value_to_key(vm, key, key);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+    }
 
     njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
 
@@ -1281,25 +1290,7 @@ njs_vmcode_property_in(njs_vm_t *vm, njs
         return ret;
     }
 
-    if (ret == NJS_DECLINED) {
-        if (!njs_is_object(value) && !njs_is_external(value)) {
-            njs_type_error(vm, "property in on a primitive value");
-
-            return NJS_ERROR;
-        }
-
-    } else {
-        prop = pq.lhq.value;
-
-        if (/* !njs_is_data_descriptor(prop) */
-            prop->writable == NJS_ATTRIBUTE_UNSET
-            || njs_is_valid(&prop->value))
-        {
-            found = 1;
-        }
-    }
-
-    njs_set_boolean(&vm->retval, found);
+    njs_set_boolean(&vm->retval, ret == NJS_OK);
 
     return sizeof(njs_vmcode_3addr_t);
 }
diff -r e5917fbde8d2 -r a41681864650 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Tue Nov 26 15:11:40 2019 +0300
+++ b/src/test/njs_unit_test.c	Tue Nov 26 13:22:09 2019 +0300
@@ -3583,6 +3583,8 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("Math.E = 1"),
       njs_str("TypeError: Cannot assign to read-only property \"E\" of object") },
 
+    /* "in" operation. */
+
     { njs_str("var o = { 'a': 1, 'b': 2 }; var i; "
                  "for (i in o) { delete o.a; delete o.b; }; njs.dump(o)"),
       njs_str("{}") },
@@ -3597,6 +3599,12 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'a' in {a:1}"),
       njs_str("true") },
 
+    { njs_str("Symbol.unscopables in { [Symbol.unscopables]: 1 }"),
+      njs_str("true") },
+
+    { njs_str("Object(Symbol.toStringTag) in Math"),
+      njs_str("true") },
+
     { njs_str("'1' in [0,,2]"),
       njs_str("false") },
 
@@ -3609,11 +3617,18 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'a' in Object.create({a:1})"),
       njs_str("true") },
 
-    { njs_str("var a = 1; 1 in a"),
-      njs_str("TypeError: property in on a primitive value") },
-
-    { njs_str("var a = true; 1 in a"),
-      njs_str("TypeError: property in on a primitive value") },
+    { njs_str("[false, NaN, '', Symbol()]"
+              ".map((x) => { "
+              "    try { 'toString' in x; } "
+              "    catch (e) { return e instanceof TypeError ? e.message : ''; } "
+              "})"
+              ".every((x) => x.startsWith('property \"in\" on primitive'))"),
+      njs_str("true") },
+
+    { njs_str("var p = new String('test');"
+              "p.toString = () => { throw new Error('failed') };"
+              "p in 1"),
+      njs_str("TypeError: property \"in\" on primitive number type") },
 
     { njs_str("var n = { toString: function() { return 'a' } };"
                  "var o = { a: 5 }; o[n]"),


More information about the nginx-devel mailing list