aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-07-30 22:08:39 +0200
committerLars Knoll <lars.knoll@qt.io>2018-07-30 20:44:55 +0000
commit26f2eabe2847a3c98d7b84b09531ff82b13fcd67 (patch)
tree4369d83ae99ec2d986ada1effb38fda8a97cc49c
parent1cde99fbafe035cbd88237d8e0a3b52b780f68af (diff)
Add support for @@unscopables
See ES7 spec, chapter 22.1.3.32 Change-Id: Ibe7df71cbc1bc848e205b9ca682f24841adfa2d9 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp35
-rw-r--r--src/qml/jsruntime/qv4context.cpp91
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations11
3 files changed, 106 insertions, 31 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 4dbb61298e..450916fbf7 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -100,15 +100,34 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineDefaultProperty(QStringLiteral("from"), method_from, 1);
ctor->addSymbolSpecies();
+ ScopedObject unscopables(scope, engine->newObject(engine->classes[EngineBase::Class_Empty]->changeVTable(QV4::Object::staticVTable())));
+ ScopedString name(scope);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0);
defineDefaultProperty(QStringLiteral("concat"), method_concat, 1);
- defineDefaultProperty(QStringLiteral("copyWithin"), method_copyWithin, 2);
- defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
- defineDefaultProperty(QStringLiteral("find"), method_find, 1);
- defineDefaultProperty(QStringLiteral("findIndex"), method_findIndex, 1);
+ name = engine->newIdentifier(QStringLiteral("copyWithin"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_copyWithin, 2);
+ name = engine->newIdentifier(QStringLiteral("entries"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_entries, 0);
+ name = engine->newIdentifier(QStringLiteral("fill"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_fill, 1);
+ name = engine->newIdentifier(QStringLiteral("find"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_find, 1);
+ name = engine->newIdentifier(QStringLiteral("findIndex"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_findIndex, 1);
+ name = engine->newIdentifier(QStringLiteral("includes"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_includes, 1);
defineDefaultProperty(QStringLiteral("join"), method_join, 1);
+ name = engine->newIdentifier(QStringLiteral("keys"));
+ unscopables->put(name, Primitive::fromBoolean(true));
+ defineDefaultProperty(name, method_keys, 0);
defineDefaultProperty(QStringLiteral("pop"), method_pop, 0);
defineDefaultProperty(QStringLiteral("push"), method_push, 1);
defineDefaultProperty(QStringLiteral("reverse"), method_reverse, 0);
@@ -117,12 +136,9 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(QStringLiteral("splice"), method_splice, 2);
defineDefaultProperty(QStringLiteral("unshift"), method_unshift, 1);
- defineDefaultProperty(QStringLiteral("includes"), method_includes, 1);
defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
- defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("every"), method_every, 1);
- defineDefaultProperty(QStringLiteral("fill"), method_fill, 1);
defineDefaultProperty(QStringLiteral("some"), method_some, 1);
defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
defineDefaultProperty(QStringLiteral("map"), method_map, 1);
@@ -132,8 +148,11 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral("values")));
ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0));
engine->jsObjects[ExecutionEngine::ArrayProtoValues] = values;
- defineDefaultProperty(QStringLiteral("values"), values);
+ unscopables->put(valuesString, Primitive::fromBoolean(true));
+ defineDefaultProperty(valuesString, values);
defineDefaultProperty(engine->symbol_iterator(), values);
+
+ defineReadonlyConfigurableProperty(engine->symbol_unscopables(), unscopables);
}
ReturnedValue ArrayPrototype::method_isArray(const FunctionObject *, const Value *, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index bb08d2786d..327e7b78c4 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -49,6 +49,7 @@
#include "qv4string_p.h"
#include "qv4qmlcontext_p.h"
#include "qv4stackframe_p.h"
+#include "qv4symbol_p.h"
using namespace QV4;
@@ -189,11 +190,27 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
scope.engine->throwTypeError();
}
+static bool unscopable(ExecutionEngine *engine, Heap::Object *withObject, PropertyKey id)
+{
+ if (!withObject)
+ return false;
+ Scope scope(engine);
+ ScopedObject w(scope, withObject);
+ ScopedObject o(scope, w->get(scope.engine->symbol_unscopables()));
+ if (o) {
+ ScopedValue blocked(scope, o->get(id));
+ return blocked->toBoolean();
+ }
+ return false;
+}
+
bool ExecutionContext::deleteProperty(String *name)
{
PropertyKey id = name->toPropertyKey();
Heap::ExecutionContext *ctx = d();
+ ExecutionEngine *engine = ctx->internalClass->engine;
+
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
case Heap::ExecutionContext::Type_BlockContext:
@@ -205,13 +222,27 @@ bool ExecutionContext::deleteProperty(String *name)
return false;
Q_FALLTHROUGH();
}
- case Heap::ExecutionContext::Type_WithContext:
+ case Heap::ExecutionContext::Type_WithContext: {
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject object(scope, ctx->activation);
+ if (object && object->hasProperty(id)) {
+ bool u = ::unscopable(engine, ctx->activation, id);
+ if (engine->hasException)
+ return false;
+ if (u)
+ break;
+ return object->deleteProperty(id);
+ }
+ }
+ break;
+ }
case Heap::ExecutionContext::Type_GlobalContext: {
if (ctx->activation) {
Scope scope(this);
ScopedObject object(scope, ctx->activation);
- if (object && object->hasProperty(name->toPropertyKey()))
- return object->deleteProperty(name->toPropertyKey());
+ if (object && object->hasProperty(id))
+ return object->deleteProperty(id);
}
break;
}
@@ -221,22 +252,27 @@ bool ExecutionContext::deleteProperty(String *name)
}
}
- return !engine()->currentStackFrame->v4Function->isStrict();
+ return !engine->currentStackFrame->v4Function->isStrict();
}
ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value &value)
{
PropertyKey id = name->toPropertyKey();
- QV4::ExecutionEngine *v4 = engine();
Heap::ExecutionContext *ctx = d();
+ QV4::ExecutionEngine *engine = ctx->internalClass->engine;
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
case Heap::ExecutionContext::Type_WithContext: {
- Scope scope(v4);
+ Scope scope(engine);
ScopedObject w(scope, ctx->activation);
- if (w->hasProperty(name->toPropertyKey())) {
+ if (w->hasProperty(id)) {
+ bool u = ::unscopable(engine, ctx->activation, id);
+ if (engine->hasException)
+ return TypeError;
+ if (u)
+ break;
if (!w->put(name, value))
return TypeError;
return NoError;
@@ -248,7 +284,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
uint index = c->internalClass->find(id);
if (index < UINT_MAX) {
- static_cast<Heap::CallContext *>(c)->locals.set(v4, index, value);
+ static_cast<Heap::CallContext *>(c)->locals.set(engine, index, value);
return NoError;
}
}
@@ -257,7 +293,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value
if (ctx->activation) {
uint member = ctx->activation->internalClass->find(id);
if (member < UINT_MAX) {
- Scope scope(v4);
+ Scope scope(engine);
ScopedObject a(scope, ctx->activation);
if (!a->putValue(member, value))
return TypeError;
@@ -266,7 +302,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value
}
break;
case Heap::ExecutionContext::Type_QmlContext: {
- Scope scope(v4);
+ Scope scope(engine);
ScopedObject activation(scope, ctx->activation);
if (!activation->put(name, value))
return TypeError;
@@ -284,6 +320,8 @@ ReturnedValue ExecutionContext::getProperty(String *name)
PropertyKey id = name->toPropertyKey();
Heap::ExecutionContext *ctx = d();
+ QV4::ExecutionEngine *engine = ctx->internalClass->engine;
+
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
case Heap::ExecutionContext::Type_BlockContext:
@@ -296,6 +334,19 @@ ReturnedValue ExecutionContext::getProperty(String *name)
Q_FALLTHROUGH();
}
case Heap::ExecutionContext::Type_WithContext:
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject activation(scope, ctx->activation);
+ if (activation->hasProperty(id)) {
+ bool u = ::unscopable(engine, ctx->activation, id);
+ if (engine->hasException)
+ return false;
+ if (u)
+ break;
+ return activation->get(id);
+ }
+ }
+ break;
case Heap::ExecutionContext::Type_GlobalContext:
case Heap::ExecutionContext::Type_QmlContext: {
if (ctx->activation) {
@@ -310,7 +361,7 @@ ReturnedValue ExecutionContext::getProperty(String *name)
}
}
}
- return engine()->throwReferenceError(*name);
+ return engine->throwReferenceError(*name);
}
ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
@@ -319,6 +370,8 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
PropertyKey id = name->toPropertyKey();
Heap::ExecutionContext *ctx = d();
+ QV4::ExecutionEngine *engine = ctx->internalClass->engine;
+
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
case Heap::ExecutionContext::Type_BlockContext:
@@ -342,6 +395,20 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
break;
}
case Heap::ExecutionContext::Type_WithContext:
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject activation(scope, ctx->activation);
+ if (activation->hasProperty(id)) {
+ bool u = ::unscopable(engine, ctx->activation, id);
+ if (engine->hasException)
+ return false;
+ if (u)
+ break;
+ base->setM(activation->d());
+ return activation->get(id);
+ }
+ }
+ break;
case Heap::ExecutionContext::Type_QmlContext: {
Scope scope(this);
ScopedObject o(scope, ctx->activation);
@@ -355,7 +422,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
}
}
}
- return engine()->throwReferenceError(*name);
+ return engine->throwReferenceError(*name);
}
void Heap::CallContext::setArg(uint index, Value v)
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index d919269b3a..6b220b963f 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -27,8 +27,6 @@ built-ins/Array/isArray/proxy.js fails
built-ins/Array/length/define-own-prop-length-overflow-realm.js fails
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_large-typed-array.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
@@ -778,13 +776,7 @@ built-ins/Proxy/getOwnPropertyDescriptor/trap-is-not-callable-realm.js fails
built-ins/Proxy/getOwnPropertyDescriptor/trap-is-undefined.js fails
built-ins/Proxy/getPrototypeOf/trap-is-not-callable-realm.js fails
built-ins/Proxy/has/call-object-create.js fails
-built-ins/Proxy/has/call-with.js sloppyFails
-built-ins/Proxy/has/return-false-target-not-extensible-using-with.js sloppyFails
-built-ins/Proxy/has/return-false-target-prop-exists-using-with.js sloppyFails
-built-ins/Proxy/has/return-false-targetdesc-not-configurable-using-with.js sloppyFails
-built-ins/Proxy/has/return-is-abrupt-with.js sloppyFails
built-ins/Proxy/has/trap-is-not-callable-realm.js fails
-built-ins/Proxy/has/trap-is-not-callable-using-with.js sloppyFails
built-ins/Proxy/isExtensible/trap-is-not-callable-realm.js fails
built-ins/Proxy/ownKeys/call-parameters-object-getownpropertynames.js fails
built-ins/Proxy/ownKeys/call-parameters-object-getownpropertysymbols.js fails
@@ -2201,7 +2193,6 @@ language/expressions/object/method-definition/yield-as-identifier-in-nested-func
language/expressions/object/method-definition/yield-as-literal-property-name.js fails
language/expressions/object/method-definition/yield-as-property-name.js fails
language/expressions/object/method-definition/yield-star-before-newline.js fails
-language/expressions/object/prop-def-id-eval-error-2.js sloppyFails
language/expressions/object/properties-names-eval-arguments.js strictFails
language/expressions/object/scope-gen-meth-body-lex-distinct.js sloppyFails
language/expressions/object/scope-gen-meth-param-elem-var-close.js sloppyFails
@@ -2658,8 +2649,6 @@ language/statements/try/tco-catch.js strictFails
language/statements/try/tco-finally.js strictFails
language/statements/variable/binding-resolution.js sloppyFails
language/statements/while/tco-body.js strictFails
-language/statements/with/binding-blocked-by-unscopables.js sloppyFails
-language/statements/with/has-property-err.js sloppyFails
language/statements/with/unscopables-inc-dec.js sloppyFails
language/types/reference/get-value-prop-base-primitive-realm.js fails
language/types/reference/put-value-prop-base-primitive-realm.js fails