aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen_p.h
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-04-09 17:42:06 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2021-04-13 19:19:56 +0200
commit5f7ecce23321f499b1b002c32a27c63815535baa (patch)
tree4e1e23e18cacd4e0d9883fc0f581a77cd3df56e6 /src/qml/compiler/qv4codegen_p.h
parent9b0069d94a5b725923e303ccdb3d7739088e06fc (diff)
Implement optional chaining
This change implements optional chaining (https://github.com/tc39/proposal-optional-chaining) by adding a new type of optional lookup with an offset to the end of a chain. If `undefined` or `null` is encountered during an access marked as optional, we jump to that end offset. Features: - Full support for all kinds of optional chain - With some codegen overhead but zero overhead during normal non-optional FieldMemberExpression resolution - Properly retains this contexts and does not need to resolve anything twice (this has been an issue previously) - No extra AST structures, just flags for existing ones [ChangeLog][QtQml] Added support for optional chaining (https://github.com/tc39/proposal-optional-chaining) Fixes: QTBUG-77926 Change-Id: I9a41cdc4ca272066c79c72b9b22206498a546843 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/compiler/qv4codegen_p.h')
-rw-r--r--src/qml/compiler/qv4codegen_p.h21
1 files changed, 18 insertions, 3 deletions
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index e7d7a21294..e720cb2973 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -60,6 +60,8 @@
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4calldata_p.h>
+#include <QtCore/qsharedpointer.h>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -277,11 +279,15 @@ public:
r.name = name;
return r;
}
- static Reference fromMember(const Reference &baseRef, const QString &name) {
+ static Reference fromMember(const Reference &baseRef, const QString &name,
+ Moth::BytecodeGenerator::Label jumpLabel = Moth::BytecodeGenerator::Label(),
+ Moth::BytecodeGenerator::Label targetLabel = Moth::BytecodeGenerator::Label()) {
Reference r(baseRef.codegen, Member);
r.propertyBase = baseRef.asRValue();
r.propertyNameIndex = r.codegen->registerString(name);
r.requiresTDZCheck = baseRef.requiresTDZCheck;
+ r.optionalChainJumpLabel.reset(new Moth::BytecodeGenerator::Label(jumpLabel));
+ r.optionalChainTargetLabel.reset(new Moth::BytecodeGenerator::Label(targetLabel));
return r;
}
static Reference fromSuperProperty(const Reference &property) {
@@ -291,13 +297,14 @@ public:
r.subscriptRequiresTDZCheck = property.requiresTDZCheck;
return r;
}
- static Reference fromSubscript(const Reference &baseRef, const Reference &subscript) {
+ static Reference fromSubscript(const Reference &baseRef, const Reference &subscript, Moth::BytecodeGenerator::Label targetLabel = Moth::BytecodeGenerator::Label()) {
Q_ASSERT(baseRef.isStackSlot());
Reference r(baseRef.codegen, Subscript);
r.elementBase = baseRef.stackSlot();
r.elementSubscript = subscript.asRValue();
r.requiresTDZCheck = baseRef.requiresTDZCheck;
r.subscriptRequiresTDZCheck = subscript.requiresTDZCheck;
+ r.optionalChainTargetLabel.reset(new Moth::BytecodeGenerator::Label(targetLabel));
return r;
}
static Reference fromConst(Codegen *cg, QV4::ReturnedValue constant) {
@@ -374,6 +381,8 @@ public:
quint32 isVolatile:1;
quint32 global:1;
quint32 qmlGlobal:1;
+ QSharedPointer<Moth::BytecodeGenerator::Label> optionalChainJumpLabel;
+ QSharedPointer<Moth::BytecodeGenerator::Label> optionalChainTargetLabel;
private:
void storeAccumulator() const;
@@ -598,11 +607,14 @@ protected:
bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
bool visit(QQmlJS::AST::BinaryExpression *ast) override;
bool visit(QQmlJS::AST::CallExpression *ast) override;
+ void endVisit(QQmlJS::AST::CallExpression *ast) override;
bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
bool visit(QQmlJS::AST::DeleteExpression *ast) override;
+ void endVisit(QQmlJS::AST::DeleteExpression *ast) override;
bool visit(QQmlJS::AST::FalseLiteral *ast) override;
bool visit(QQmlJS::AST::SuperLiteral *ast) override;
bool visit(QQmlJS::AST::FieldMemberExpression *ast) override;
+ void endVisit(QQmlJS::AST::FieldMemberExpression *ast) override;
bool visit(QQmlJS::AST::TaggedTemplate *ast) override;
bool visit(QQmlJS::AST::FunctionExpression *ast) override;
bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
@@ -686,7 +698,7 @@ public:
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
struct Arguments { int argc; int argv; bool hasSpread; };
Arguments pushArgs(QQmlJS::AST::ArgumentList *args);
- void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
+ void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject, bool optional = false);
Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
@@ -776,6 +788,8 @@ protected:
bool functionEndsWithReturn = false;
bool _tailCallsAreAllowed = true;
QSet<QString> m_globalNames;
+ QSet<QQmlJS::AST::Node*> m_seenOptionalChainNodes;
+ QHash<QQmlJS::AST::Node*, Moth::BytecodeGenerator::Label> m_optionalChainLabels;
ControlFlow *controlFlow = nullptr;
@@ -812,6 +826,7 @@ private:
void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
void throwError(ErrorType errorType, const QQmlJS::SourceLocation &loc,
const QString &detail);
+ std::optional<Moth::BytecodeGenerator::Label> traverseOptionalChain(QQmlJS::AST::Node *node);
};
}