diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2019-07-03 15:13:46 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2019-07-09 16:52:55 +0200 |
commit | 910f98031fdd834a22af0da21c9ff6ae145f61c5 (patch) | |
tree | 03062e2ec8ccca2a1bbdc2c6e69587de1eedbe76 /src | |
parent | f2cb10ebc4946b10526fa22581913ccc04cea164 (diff) |
Add support for C++ accessible typed parameters and return types in qml functions
These can be declared using the new typescript-like syntax and using
type names that are also used for signal parameters and property types.
This merely affects their signature on the C++ side and allows the
corresponding invocation.
Change-Id: Icaed4ee0dc7aa71330f99d96e073a2a63d409bbe
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 33 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 59 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 18 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 4 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 25 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlirloader.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 28 |
14 files changed, 153 insertions, 70 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a94a448ec0..6dc6f191ab 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -66,19 +66,31 @@ using namespace QmlIR; bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString ¶meterName, const QString &typeName) { - nameIndex = stringGenerator->registerString(parameterName); - type.indexIsBuiltinType = false; - type.typeNameIndexOrBuiltinType = 0; + return init(this, stringGenerator, stringGenerator->registerString(parameterName), stringGenerator->registerString(typeName)); +} + +bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator, + int parameterNameIndex, int typeNameIndex) +{ + param->nameIndex = parameterNameIndex; + return initType(¶m->type, stringGenerator, typeNameIndex); +} + +bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex) +{ + paramType->indexIsBuiltinType = false; + paramType->typeNameIndexOrBuiltinType = 0; + const QString typeName = stringGenerator->stringForIndex(typeNameIndex); auto builtinType = stringToBuiltinType(typeName); if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) { if (typeName.isEmpty() || !typeName.at(0).isUpper()) return false; - type.indexIsBuiltinType = false; - type.typeNameIndexOrBuiltinType = stringGenerator->registerString(typeName); - Q_ASSERT(quint32(stringGenerator->getStringId(typeName)) < (1u << 31)); + paramType->indexIsBuiltinType = false; + paramType->typeNameIndexOrBuiltinType = typeNameIndex; + Q_ASSERT(quint32(typeNameIndex) < (1u << 31)); } else { - type.indexIsBuiltinType = true; - type.typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType); + paramType->indexIsBuiltinType = true; + paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType); Q_ASSERT(quint32(builtinType) < (1u << 31)); } return true; @@ -909,13 +921,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) f->index = index; f->nameIndex = registerString(funDecl->name.toString()); + QString returnTypeName = funDecl->typeAnnotation ? funDecl->typeAnnotation->type->toString() : QString(); + Parameter::initType(&f->returnType, jsGenerator, registerString(returnTypeName)); + const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames(); int formalsCount = formals.size(); f->formals.allocate(pool, formalsCount); int i = 0; for (const auto &arg : formals) { - f->formals[i] = registerString(arg.id); + f->formals[i].init(jsGenerator, arg.id, arg.typeName()); ++i; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 44d6233d91..e04fb923c3 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -221,6 +221,10 @@ struct Parameter : public QV4::CompiledData::Parameter Parameter *next; bool init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString ¶meterName, const QString &typeName); + static bool init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator, + int parameterNameIndex, int typeNameIndex); + static bool initType(QV4::CompiledData::ParameterType *paramType, + const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex); static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName); }; @@ -265,11 +269,12 @@ struct Function QV4::CompiledData::Location location; int nameIndex; quint32 index; // index in parsedQML::functions - FixedPoolArray<int> formals; + FixedPoolArray<Parameter> formals; + QV4::CompiledData::ParameterType returnType; // --- QQmlPropertyCacheCreator interface - const int *formalsBegin() const { return formals.begin(); } - const int *formalsEnd() const { return formals.end(); } + const Parameter *formalsBegin() const { return formals.begin(); } + const Parameter *formalsEnd() const { return formals.end(); } // --- Function *next; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 8a40255062..b542d7f918 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -74,7 +74,7 @@ QT_BEGIN_NAMESPACE // Also change the comment behind the number to describe the latest change. This has the added // benefit that if another patch changes the version too, it will result in a merge conflict, and // not get removed silently. -#define QV4_DATA_STRUCTURE_VERSION 0x23 // Remove trace slots +#define QV4_DATA_STRUCTURE_VERSION 0x24 // Collect function parameter types class QIODevice; class QQmlPropertyData; @@ -257,6 +257,29 @@ struct Block }; static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +enum class BuiltinType : unsigned int { + Var = 0, Variant, Int, Bool, Real, String, Url, Color, + Font, Time, Date, DateTime, Rect, Point, Size, + Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin +}; + +struct ParameterType +{ + union { + quint32 _dummy; + quint32_le_bitfield<0, 1> indexIsBuiltinType; + quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; + }; +}; +static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); + +struct Parameter +{ + quint32_le nameIndex; + ParameterType type; +}; +static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); + // Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties // for unaligned access. The ordering of the fields is also from largest to smallest. struct Function @@ -275,6 +298,7 @@ struct Function quint16_le length; quint16_le nFormals; quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData. + ParameterType returnType; quint32_le localsOffset; quint16_le nLocals; quint16_le nLineNumbers; @@ -296,13 +320,13 @@ struct Function // quint32 formalsIndex[nFormals] // quint32 localsIndex[nLocals] - const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); } + const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); } const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); } const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); } // --- QQmlPropertyCacheCreator interface - const quint32_le *formalsBegin() const { return formalsTable(); } - const quint32_le *formalsEnd() const { return formalsTable() + nFormals; } + const Parameter *formalsBegin() const { return formalsTable(); } + const Parameter *formalsEnd() const { return formalsTable() + nFormals; } // --- const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); } @@ -310,7 +334,7 @@ struct Function const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; } static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) { - int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32) + int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32) + nLines*sizeof(CodeOffsetToLine); size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize); Q_ASSERT(size < INT_MAX); @@ -321,7 +345,7 @@ struct Function return (a + 7) & ~size_t(7); } }; -static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Method { enum Type { @@ -604,29 +628,6 @@ struct Enum }; static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); -enum class BuiltinType : unsigned int { - Var = 0, Variant, Int, Bool, Real, String, Url, Color, - Font, Time, Date, DateTime, Rect, Point, Size, - Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin -}; - -struct ParameterType -{ - union { - quint32 _dummy; - quint32_le_bitfield<0, 1> indexIsBuiltinType; - quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; - }; -}; -static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); - -struct Parameter -{ - quint32_le nameIndex; - ParameterType type; -}; -static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); - struct Signal { quint32_le nameIndex; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 7329d526c1..22f393eaec 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -45,6 +45,7 @@ #include <private/qqmljslexer_p.h> #include <private/qqmljsast_p.h> #include <private/qml_compile_hash_p.h> +#include <private/qqmlirbuilder_p.h> #include <QCryptographicHash> // Efficient implementation that takes advantage of powers of two. @@ -268,8 +269,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO registerString(module->finalUrl); for (Context *f : qAsConst(module->functions)) { registerString(f->name); - for (int i = 0; i < f->arguments.size(); ++i) + registerString(f->returnType); + for (int i = 0; i < f->arguments.size(); ++i) { registerString(f->arguments.at(i).id); + registerString(f->arguments.at(i).typeName()); + } for (int i = 0; i < f->locals.size(); ++i) registerString(f->locals.at(i)); } @@ -436,7 +440,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte function->length = irFunction->formals ? irFunction->formals->length() : 0; function->nFormals = irFunction->arguments.size(); function->formalsOffset = currentOffset; - currentOffset += function->nFormals * sizeof(quint32); + currentOffset += function->nFormals * sizeof(CompiledData::Parameter); + + QmlIR::Parameter::initType(&function->returnType, this, getStringId(irFunction->returnType)); function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone; function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone; @@ -465,9 +471,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte function->codeSize = irFunction->code.size(); // write formals - quint32_le *formals = (quint32_le *)(f + function->formalsOffset); - for (int i = 0; i < irFunction->arguments.size(); ++i) - formals[i] = getStringId(irFunction->arguments.at(i).id); + CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset); + for (int i = 0; i < irFunction->arguments.size(); ++i) { + QmlIR::Parameter::init(&formals[i], this, getStringId(irFunction->arguments.at(i).id), + getStringId(irFunction->arguments.at(i).typeName())); + } // write locals quint32_le *locals = (quint32_le *)(f + function->localsOffset); diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index e7ba13ec20..1ae7c8c149 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -190,6 +190,7 @@ struct Context { QSet<QString> usedVariables; QQmlJS::AST::FormalParameterList *formals = nullptr; QQmlJS::AST::BoundNames arguments; + QString returnType; QStringList locals; QStringList moduleRequests; QVector<ImportEntry> importEntries; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 9eaf0adf70..003c32a8fe 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -680,10 +680,8 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete else if (expr->isGenerator) _context->isGenerator = true; - if (expr->typeAnnotation) { - _cg->throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Type annotations are not supported (yet).")); - return false; - } + if (expr->typeAnnotation) + _context->returnType = expr->typeAnnotation->type->toString(); } @@ -700,10 +698,6 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete const BoundNames boundNames = formals ? formals->boundNames() : BoundNames(); for (int i = 0; i < boundNames.size(); ++i) { - if (auto type = boundNames.at(i).typeAnnotation) { - _cg->throwSyntaxError(type->firstSourceLocation(), QLatin1String("Type annotations are not supported (yet).")); - return false; - } const QString &arg = boundNames.at(i).id; if (_context->isStrict || !isSimpleParameterList) { bool duplicate = (boundNames.indexOf(arg, i + 1) != -1); @@ -721,6 +715,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete if (!_context->arguments.contains(arg)) _context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var); } + return true; } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index d870cec68a..aeb4835c40 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -100,9 +100,9 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, for (quint32 i = 0; i < compiledFunction->nLocals; ++i) ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); - const quint32_le *formalsIndices = compiledFunction->formalsTable(); + const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable(); for (quint32 i = 0; i < compiledFunction->nFormals; ++i) - ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable); + ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable); internalClass = ic->d(); nFormals = compiledFunction->nFormals; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 4f70bf0004..700c191499 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1511,6 +1511,31 @@ void UiVersionSpecifier::accept0(Visitor *visitor) } visitor->endVisit(this); } + +QString Type::toString() const +{ + QString result; + toString(&result); + return result; +} + +void Type::toString(QString *out) const +{ + for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) { + out->append(it->name); + + if (it->next) + out->append(QLatin1Char('.')); + } + + if (typeArguments) { + out->append(QLatin1Char('<')); + if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId) + subType->toString(out); + out->append(QLatin1Char('>')); + }; +} + } } // namespace QQmlJS::AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index da8d0bcd8d..ea854c3754 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -364,6 +364,9 @@ public: SourceLocation lastSourceLocation() const override { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); } + QString toString() const; + void toString(QString *out) const; + // attributes UiQualifiedId *typeId; Node *typeArguments; // TypeArgumentList @@ -838,6 +841,7 @@ struct QML_PARSER_EXPORT BoundName : id(id), typeAnnotation(typeAnnotation) {} BoundName() = default; + QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); } }; struct BoundNames : public QVector<BoundName> diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp index 8c01c81e7d..82cad8eba8 100644 --- a/src/qml/qml/qqmlirloader.cpp +++ b/src/qml/qml/qqmlirloader.cpp @@ -188,11 +188,12 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali f->index = functionIndices.count() - 1; f->location = compiledFunction->location; f->nameIndex = compiledFunction->nameIndex; + f->returnType = compiledFunction->returnType; f->formals.allocate(pool, int(compiledFunction->nFormals)); - const quint32_le *formalNameIdx = compiledFunction->formalsTable(); + const QV4::CompiledData::Parameter *formalNameIdx = compiledFunction->formalsTable(); for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) - f->formals[i] = *formalNameIdx; + *static_cast<QV4::CompiledData::Parameter*>(&f->formals[i]) = *formalNameIdx; object->functions->append(f); } diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 48c4216d54..69957ab282 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -348,17 +348,18 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag } void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags, - int coreIndex, const QList<QByteArray> &names) + int coreIndex, int returnType, const QList<QByteArray> &names, + const QVector<int> ¶meterTypes) { int argumentCount = names.count(); QQmlPropertyData data; - data.setPropType(QMetaType::QVariant); + data.setPropType(returnType); data.setCoreIndex(coreIndex); QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); for (int ii = 0; ii < argumentCount; ++ii) - args->arguments[ii + 1] = QMetaType::QVariant; + args->arguments[ii + 1] = parameterTypes.at(ii); args->argumentsValid = true; data.setArguments(args); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 72692ee522..bfd78eef88 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -103,8 +103,8 @@ public: int propType, int revision, int notifyIndex); void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex, const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>()); - void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, - const QList<QByteArray> &names = QList<QByteArray>()); + void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, int returnType, + const QList<QByteArray> &names, const QVector<int> ¶meterTypes); void appendEnum(const QString &, const QVector<QQmlEnumValue> &); const QMetaObject *metaObject() const; diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index a207ea7e86..247145ac0c 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -453,14 +453,23 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea // protect against overriding change signals or methods with properties. QList<QByteArray> parameterNames; + QVector<int> parameterTypes; auto formal = function->formalsBegin(); auto end = function->formalsEnd(); for ( ; formal != end; ++formal) { flags.hasArguments = true; - parameterNames << stringAt(*formal).toUtf8(); + parameterNames << stringAt(formal->nameIndex).toUtf8(); + int type = metaTypeForParameter(formal->type); + if (type == QMetaType::UnknownType) + type = QMetaType::QVariant; + parameterTypes << type; } - cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); + int returnType = metaTypeForParameter(function->returnType); + if (returnType == QMetaType::UnknownType) + returnType = QMetaType::QVariant; + + cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes); } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 458f26b465..b9d8fed243 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -58,6 +58,7 @@ #include <private/qv4jscall_p.h> #include <private/qv4qobjectwrapper_p.h> #include <private/qqmlpropertycachecreator_p.h> +#include <private/qqmlpropertycachemethodarguments_p.h> QT_BEGIN_NAMESPACE @@ -917,21 +918,38 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; // The dynamic method with that id is not available. } - const unsigned int parameterCount = function->formalParameterCount(); + auto methodData = cache->method(_id); + auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr; + + const unsigned int parameterCount = (arguments && arguments->names) ? arguments->names->count() : 0; + Q_ASSERT(parameterCount == function->formalParameterCount()); + QV4::JSCallData jsCallData(scope, parameterCount); *jsCallData->thisObject = v4->global(); - for (uint ii = 0; ii < parameterCount; ++ii) - jsCallData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]); + for (uint ii = 0; ii < parameterCount; ++ii) { + jsCallData->args[ii] = scope.engine->metaTypeToJS(arguments->arguments[ii + 1], a[ii + 1]); + } + const int returnType = methodData->propType(); QV4::ScopedValue result(scope, function->call(jsCallData)); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); if (error.isValid()) ep->warning(error); - if (a[0]) *(QVariant *)a[0] = QVariant(); + if (a[0]) { + QMetaType::destruct(returnType, a[0]); + QMetaType::construct(returnType, a[0], nullptr); + } } else { - if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0); + if (a[0]) { + // When the return type is QVariant, JS objects are to be returned as QJSValue wrapped in + // QVariant. + if (returnType == QMetaType::QVariant) + *(QVariant *)a[0] = scope.engine->toVariant(result, 0); + else + scope.engine->metaTypeFromJS(result, returnType, a[0]); + } } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. |