aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp33
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h11
-rw-r--r--src/qml/compiler/qv4compileddata_p.h59
-rw-r--r--src/qml/compiler/qv4compiler.cpp18
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h1
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp11
-rw-r--r--src/qml/jsruntime/qv4function.cpp4
-rw-r--r--src/qml/parser/qqmljsast.cpp25
-rw-r--r--src/qml/parser/qqmljsast_p.h4
-rw-r--r--src/qml/qml/qqmlirloader.cpp5
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp7
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h4
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h13
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp28
-rw-r--r--tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.3.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.3.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp27
20 files changed, 185 insertions, 88 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 &parameterName,
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(&param->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 &parameterName, 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> &parameterTypes)
{
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> &parameterTypes);
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.
diff --git a/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
new file mode 100644
index 0000000000..26931a4f10
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0 as QQ
+import QtQml 2.0 as Core
+QQ.Item {
+ id: root
+ function returnItem() : Core.QtObject { return root; }
+ function takeString(arg: string) { return arg; }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.errors.txt b/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.errors.txt
deleted file mode 100644
index 141ea9c7bc..0000000000
--- a/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.errors.txt
+++ /dev/null
@@ -1 +0,0 @@
-4:26:Type annotations are not supported (yet).
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.qml b/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.qml
deleted file mode 100644
index 03272e9d50..0000000000
--- a/tests/auto/qml/qqmllanguage/data/typeAnnotations.3.qml
+++ /dev/null
@@ -1,7 +0,0 @@
-import QtQml 2.0
-
-QtObject {
- function notYet(param: string) {
- return param
- }
-}
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.errors.txt b/tests/auto/qml/qqmllanguage/data/typeAnnotations.errors.txt
deleted file mode 100644
index 3db89a47d5..0000000000
--- a/tests/auto/qml/qqmllanguage/data/typeAnnotations.errors.txt
+++ /dev/null
@@ -1 +0,0 @@
-4:5:Type annotations are not supported (yet).
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.qml b/tests/auto/qml/qqmllanguage/data/typeAnnotations.qml
deleted file mode 100644
index d8cc4535eb..0000000000
--- a/tests/auto/qml/qqmllanguage/data/typeAnnotations.qml
+++ /dev/null
@@ -1,7 +0,0 @@
-import QtQml 2.0
-
-QtObject {
- function notYet() : string {
- return "ko"
- }
-}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index ac7874b701..11e46beb41 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -208,6 +208,7 @@ private slots:
void remoteLoadCrash();
void signalWithDefaultArg();
void signalParameterTypes();
+ void functionParameterTypes();
// regression tests for crashes
void crash1();
@@ -623,9 +624,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false;
- QTest::newRow("typeAnnotations") << "typeAnnotations.qml" << "typeAnnotations.errors.txt" << false;
QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
- QTest::newRow("typeAnnotations.3") << "typeAnnotations.3.qml" << "typeAnnotations.3.errors.txt" << false;
}
@@ -3702,6 +3701,30 @@ void tst_qqmllanguage::signalParameterTypes()
}
}
+void tst_qqmllanguage::functionParameterTypes()
+{
+ QQmlComponent component(&engine, testFileUrl("functionParameterTypes.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(!obj.isNull(), qPrintable(component.errorString()));
+ const QMetaObject *metaObject = obj->metaObject();
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("returnItem()"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.returnType(), QMetaType::type("QObject*"));
+ QObject *returnedPtr = nullptr;
+ slot.invoke(obj.data(), Qt::DirectConnection, Q_RETURN_ARG(QObject*, returnedPtr));
+ QCOMPARE(returnedPtr, obj.data());
+ }
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("takeString(QString)"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.parameterCount(), 1);
+ QCOMPARE(slot.parameterType(0), int(QMetaType::QString));
+ }
+}
+
// QTBUG-20639
void tst_qqmllanguage::globalEnums()
{