aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-30 12:58:55 +0200
committerLars Knoll <lars.knoll@qt.io>2018-08-31 06:08:41 +0000
commitee565b3db656b5b9bfd57d98d53b898c1a62e1f0 (patch)
tree857b0f3c09144e68ee0d6cfdf25a227df2f76c8b
parentebf9365b5c7ec1e4828be88beeb930b4de52f35b (diff)
Correctly create methods for functions in object literals
Methods behave slightly different than normal functions as they have a home object and define how super property access is being done. To implement this correctly, we need to create these methods during object initialization time. Change-Id: Ib3f670c8790b882c6472de786938ca4f0b73f66f Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qv4codegen.cpp24
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp30
-rw-r--r--src/qml/parser/qqmljs.g4
-rw-r--r--src/qml/parser/qqmljsast.cpp2
-rw-r--r--src/qml/parser/qqmljsast_p.h1
6 files changed, 48 insertions, 14 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 412d787d11..b09deb1eaf 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2450,7 +2450,7 @@ bool Codegen::visit(ObjectPattern *ast)
for (; it; it = it->next) {
PatternProperty *p = it->property;
AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
- if (cname || p->type == PatternProperty::Getter || p->type == PatternProperty::Setter)
+ if (cname || p->type != PatternProperty::Literal)
break;
QString name = p->name->asString();
uint arrayIndex = QV4::String::toArrayIndex(name);
@@ -2477,7 +2477,9 @@ bool Codegen::visit(ObjectPattern *ast)
PatternProperty *p = it->property;
AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
- if (p->type == PatternProperty::Getter)
+ if (p->type == PatternProperty::Method)
+ argType = ObjectLiteralArgument::Method;
+ else if (p->type == PatternProperty::Getter)
argType = ObjectLiteralArgument::Getter;
else if (p->type == PatternProperty::Setter)
argType = ObjectLiteralArgument::Setter;
@@ -2508,10 +2510,20 @@ bool Codegen::visit(ObjectPattern *ast)
push(Reference::fromAccumulator(this));
{
RegisterScope innerScope(this);
- Reference value = expression(p->initializer);
- if (hasError)
- return false;
- value.loadInAccumulator();
+ if (p->type != PatternProperty::Literal) {
+ // need to get the closure id for the method
+ FunctionExpression *f = p->initializer->asFunctionDefinition();
+ Q_ASSERT(f);
+ int function = defineFunction(f->name.toString(), f, f->formals, f->body);
+ if (hasError)
+ return false;
+ Reference::fromConst(this, Encode(function)).loadInAccumulator();
+ } else {
+ Reference value = expression(p->initializer);
+ if (hasError)
+ return false;
+ value.loadInAccumulator();
+ }
}
push(Reference::fromAccumulator(this));
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index f89a4b9909..c53465d24e 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -383,6 +383,7 @@ typedef QVector<StackFrame> StackTrace;
enum class ObjectLiteralArgument {
Value,
+ Method,
Getter,
Setter
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 3317003ea4..fbddcb6ee1 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1529,30 +1529,48 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId
ScopedProperty pd(scope);
ScopedFunctionObject fn(scope);
ScopedString fnName(scope);
+ ScopedValue value(scope);
for (int i = 0; i < additionalArgs; ++i) {
Q_ASSERT(args->isInteger());
ObjectLiteralArgument arg = ObjectLiteralArgument(args->integerValue());
name = args[1].toPropertyKey(engine);
+ value = args[2];
if (engine->hasException)
return Encode::undefined();
- if (args[2].isFunctionObject()) {
- fn = static_cast<const FunctionObject &>(args[2]);
+ if (arg != ObjectLiteralArgument::Value) {
+ Q_ASSERT(args[2].isInteger());
+ int functionId = args[2].integerValue();
+ QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
+ Q_ASSERT(clos);
+
PropertyKey::FunctionNamePrefix prefix = PropertyKey::None;
if (arg == ObjectLiteralArgument::Getter)
prefix = PropertyKey::Getter;
else if (arg == ObjectLiteralArgument::Setter)
prefix = PropertyKey::Setter;
-
+ else
+ arg = ObjectLiteralArgument::Value;
fnName = name->asFunctionName(engine, prefix);
+
+ ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ if (clos->isGenerator())
+ value = MemberGeneratorFunction::create(current, clos, fnName)->asReturnedValue();
+ else
+ value = FunctionObject::createMemberFunction(current, clos, fnName)->asReturnedValue();
+ } else if (args[2].isFunctionObject()) {
+ fn = static_cast<const FunctionObject &>(args[2]);
+
+ fnName = name->asFunctionName(engine, PropertyKey::None);
fn->setName(fnName);
}
- Q_ASSERT(arg == ObjectLiteralArgument::Value || args[2].isFunctionObject());
+ Q_ASSERT(arg != ObjectLiteralArgument::Method);
+ Q_ASSERT(arg == ObjectLiteralArgument::Value || value->isFunctionObject());
if (arg == ObjectLiteralArgument::Value || arg == ObjectLiteralArgument::Getter) {
- pd->value = args[2];
+ pd->value = value;
pd->set = Primitive::emptyValue();
} else {
pd->value = Primitive::emptyValue();
- pd->set = args[2];
+ pd->set = value;
}
bool ok = o->defineOwnProperty(name, pd, (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor));
if (!ok)
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index b5e63fe7fe..a844e3cb3e 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -3669,7 +3669,7 @@ MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN Function
f->rparenToken = loc(4);
f->lbraceToken = loc(5);
f->rbraceToken = loc(7);
- AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
@@ -3685,7 +3685,7 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R
f->lbraceToken = loc(6);
f->rbraceToken = loc(8);
f->isGenerator = true;
- AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 9484b53a39..4ebb2d3b5c 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -465,6 +465,8 @@ bool PatternProperty::convertLiteralToAssignmentPattern(MemoryPool *pool, Source
*errorMessage = QString::fromLatin1("Invalid getter/setter in destructuring expression.");
return false;
}
+ if (type == Method)
+ type = Literal;
Q_ASSERT(type == Literal);
return PatternElement::convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage);
}
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index b69fb6272b..72c47cbe32 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -670,6 +670,7 @@ public:
enum Type {
// object literal types
Literal,
+ Method,
Getter,
Setter,