aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp29
-rw-r--r--src/qml/jsruntime/qv4object.cpp27
-rw-r--r--src/qml/jsruntime/qv4object_p.h3
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations20
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