diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-08-30 12:58:55 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-08-31 06:08:41 +0000 |
commit | ee565b3db656b5b9bfd57d98d53b898c1a62e1f0 (patch) | |
tree | 857b0f3c09144e68ee0d6cfdf25a227df2f76c8b /src | |
parent | ebf9365b5c7ec1e4828be88beeb930b4de52f35b (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>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4global_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 30 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 4 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 1 |
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, |