aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2019-07-03 15:13:46 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2019-07-09 16:52:55 +0200
commit910f98031fdd834a22af0da21c9ff6ae145f61c5 (patch)
tree03062e2ec8ccca2a1bbdc2c6e69587de1eedbe76 /src/qml/compiler
parentf2cb10ebc4946b10526fa22581913ccc04cea164 (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/qml/compiler')
-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
6 files changed, 79 insertions, 54 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;
}