diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-07-03 17:21:31 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-07-30 20:44:50 +0000 |
commit | 1cde99fbafe035cbd88237d8e0a3b52b780f68af (patch) | |
tree | ccc1057c42f6e2768323f1caa069f2236c6163f3 | |
parent | 55d0327ddf2b7b59d686218a9eb7f340732136ef (diff) |
Make Array.prototype.concat comply better with the spec
There are still some failures in the test cases, but at least
less than before.
Change-Id: I5bad4ddb1e9d6fe120e981f806a6d986fd43b64d
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 29 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 27 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/ecmascripttests/TestExpectations | 20 |
4 files changed, 50 insertions, 29 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 05f6b7dfec..4dbb61298e 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -364,22 +364,31 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value ScopedArrayObject result(scope, scope.engine->newArrayObject()); - if (thisObject->isArrayObject()) { - result->copyArrayData(thisObject); - } else { - result->arraySet(0, thisObject); - } - ScopedArrayObject elt(scope); ScopedObject eltAsObj(scope); ScopedValue entry(scope); - for (int i = 0, ei = argc; i < ei; ++i) { - eltAsObj = argv[i]; - elt = argv[i]; + for (int i = -1; i < argc; ++i) { + const Value *v = i == -1 ? thisObject.getPointer() : argv + i; + eltAsObj = *v; + elt = *v; if (elt) { uint n = elt->getLength(); uint newLen = ArrayData::append(result, elt, n); result->setArrayLengthUnchecked(newLen); + } else if (eltAsObj && eltAsObj->isConcatSpreadable()) { + const uint startIndex = result->getLength(); + const uint len = eltAsObj->getLength(); + if (scope.engine->hasException) + return Encode::undefined(); + + for (uint i = 0; i < len; ++i) { + bool hasProperty = false; + entry = eltAsObj->get(i, &hasProperty); + if (hasProperty) { + if (!result->put(startIndex + i, entry)) + return scope.engine->throwTypeError(); + } + } } else if (eltAsObj && eltAsObj->isListType()) { const uint startIndex = result->getLength(); for (int i = 0, len = eltAsObj->getLength(); i < len; ++i) { @@ -388,7 +397,7 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value result->put(startIndex + i, entry); } } else { - result->arraySet(result->getLength(), argv[i]); + result->arraySet(result->getLength(), *v); } } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index e4d670d4f3..718bfbe5ec 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -51,6 +51,7 @@ #include "qv4identifiertable_p.h" #include "qv4jscall_p.h" #include "qv4symbol_p.h" +#include "qv4proxy_p.h" #include <stdint.h> @@ -930,6 +931,32 @@ void Object::initSparseArray() ArrayData::realloc(this, Heap::ArrayData::Sparse, 0, false); } +bool Object::isConcatSpreadable() const +{ + Scope scope(this); + ScopedValue spreadable(scope, get(scope.engine->symbol_isConcatSpreadable())); + if (!spreadable->isUndefined()) + return spreadable->toBoolean(); + return isArray(); +} + +bool Object::isArray() const +{ + if (isArrayObject()) + return true; + if (vtable() == ProxyObject::staticVTable()) { + const ProxyObject *p = static_cast<const ProxyObject *>(this); + Scope scope(this); + if (!p->d()->handler) { + scope.engine->throwTypeError(); + return false; + } + ScopedObject o(scope, p->d()->target); + return o->isArray(); + } + return false; +} + DEFINE_OBJECT_VTABLE(ArrayObject); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index dea080f98a..a9ad926289 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -359,6 +359,9 @@ public: ReturnedValue instanceOf(const Value &var) const { return vtable()->instanceOf(this, var); } + bool isConcatSpreadable() const; + bool isArray() const; + protected: static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *); static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index dbf2e22c63..d919269b3a 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -29,42 +29,24 @@ built-ins/Array/of/proto-from-ctor-realm.js fails built-ins/Array/proto-from-ctor-realm.js fails built-ins/Array/prototype/Symbol.unscopables/prop-desc.js fails built-ins/Array/prototype/Symbol.unscopables/value.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-length-to-string-throws.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-length-value-of-throws.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-negative-length.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-primitive-non-number-length.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-string-length.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like-to-length-throws.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_array-like.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_holey-sloppy-arguments.js fails built-ins/Array/prototype/concat/Array.prototype.concat_large-typed-array.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_length-throws.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-throws.js fails built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-with-dupes.js sloppyFails built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments.js fails built-ins/Array/prototype/concat/Array.prototype.concat_small-typed-array.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-boolean-wrapper.js fails built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-function.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-getter-throws.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-number-wrapper.js fails built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-reg-exp.js fails built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-sparse-object.js fails -built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-string-wrapper.js fails built-ins/Array/prototype/concat/Array.prototype.concat_strict-arguments.js fails +built-ins/Array/prototype/concat/S15.4.4.4_A3_T1.js fails built-ins/Array/prototype/concat/S15.4.4.4_A3_T2.js fails built-ins/Array/prototype/concat/S15.4.4.4_A3_T3.js fails built-ins/Array/prototype/concat/create-ctor-non-object.js fails built-ins/Array/prototype/concat/create-proto-from-ctor-realm-array.js fails built-ins/Array/prototype/concat/create-proto-from-ctor-realm-non-array.js fails built-ins/Array/prototype/concat/create-proxy.js fails -built-ins/Array/prototype/concat/create-revoked-proxy.js fails built-ins/Array/prototype/concat/create-species-non-ctor.js fails built-ins/Array/prototype/concat/create-species.js fails -built-ins/Array/prototype/concat/is-concat-spreadable-is-array-proxy-revoked.js fails -built-ins/Array/prototype/concat/is-concat-spreadable-proxy-revoked.js fails -built-ins/Array/prototype/concat/is-concat-spreadable-proxy.js fails built-ins/Array/prototype/concat/is-concat-spreadable-val-falsey.js fails -built-ins/Array/prototype/concat/is-concat-spreadable-val-truthy.js fails built-ins/Array/prototype/every/15.4.4.16-3-29.js fails built-ins/Array/prototype/filter/create-ctor-non-object.js fails built-ins/Array/prototype/filter/create-proto-from-ctor-realm-array.js fails |