aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-07-03 17:21:31 +0200
committerLars Knoll <lars.knoll@qt.io>2018-07-30 20:44:50 +0000
commit1cde99fbafe035cbd88237d8e0a3b52b780f68af (patch)
treeccc1057c42f6e2768323f1caa069f2236c6163f3 /src/qml/jsruntime
parent55d0327ddf2b7b59d686218a9eb7f340732136ef (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>
Diffstat (limited to 'src/qml/jsruntime')
-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
3 files changed, 49 insertions, 10 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);