From: Artem S. Povalyukhin Date: Tue, 26 Nov 2019 10:22:09 +0000 (+0300) Subject: Fixed operator "in" according to the specification. X-Git-Tag: 0.3.8~48 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=b759d244deaf8787ed7abf5c0aab2503fd2b7bb3;p=njs.git Fixed operator "in" according to the specification. --- diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index 10154544..a7de5227 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -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_value_t *value, njs_value_t *key) 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 --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index bceb715c..7d91d739 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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("[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 a = true; 1 in a"), - njs_str("TypeError: property in on a primitive value") }, + { 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]"),