[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