aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/common/qv4staticvalue_p.h1
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp6
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h2
-rw-r--r--src/qml/debugger/qqmlconfigurabledebugservice_p.h4
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc4
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc97
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc3
-rw-r--r--src/qml/jsapi/qjsengine_p.h4
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp4
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp201
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h7
-rw-r--r--src/qml/parser/qqmljs.g8
-rw-r--r--src/qml/parser/qqmljsast_p.h4
-rw-r--r--src/qml/qml/qqml.cpp20
-rw-r--r--src/qml/qml/qqml.h9
-rw-r--r--src/qml/qml/qqmlengine.cpp13
-rw-r--r--src/qml/qml/qqmlerror.cpp5
-rw-r--r--src/qml/qml/qqmlimport.cpp17
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmlmetatype_p.h4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp6
-rw-r--r--src/qml/qml/qqmlprivate.h7
-rw-r--r--src/qml/qml/qqmlproperty.cpp12
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp12
-rw-r--r--src/qml/types/qqmlbind.cpp27
28 files changed, 376 insertions, 111 deletions
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index 8160bbb748..0716f7ea20 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -51,6 +51,7 @@
//
#include <QtCore/private/qnumeric_p.h>
+#include <cstring>
#ifdef QT_NO_DEBUG
#define QV4_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index aab3f8e9d6..171dc641d3 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -908,7 +908,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
{
- if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
+ if (QQmlJS::AST::FunctionExpression *funDecl = node->sourceElement->asFunctionDefinition()) {
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
foe->node = funDecl;
foe->parentNode = funDecl;
@@ -1770,7 +1770,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
for (const CompiledFunctionOrExpression &f : functions) {
Q_ASSERT(f.node != document->program);
Q_ASSERT(f.parentNode && f.parentNode != document->program);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
+ auto function = f.node->asFunctionDefinition();
if (function) {
scan.enterQmlFunction(function);
@@ -1794,7 +1794,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QQmlJS::AST::Node *node = qmlFunction.node;
Q_ASSERT(node != document->program);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(node);
+ QQmlJS::AST::FunctionExpression *function = node->asFunctionDefinition();
QString name;
if (function)
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index f67db030a2..2de80eac44 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -88,7 +88,7 @@ public:
const QString &name);
void leaveEnvironment();
- void enterQmlFunction(QQmlJS::AST::FunctionDeclaration *ast)
+ void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
{ enterFunction(ast, false); }
protected:
diff --git a/src/qml/debugger/qqmlconfigurabledebugservice_p.h b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
index 96ec46f475..38f41047c0 100644
--- a/src/qml/debugger/qqmlconfigurabledebugservice_p.h
+++ b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
@@ -64,7 +64,7 @@ class QQmlConfigurableDebugService : public Base
{
protected:
QQmlConfigurableDebugService(float version, QObject *parent = nullptr) :
- Base(version, parent), m_configMutex(QMutex::Recursive)
+ Base(version, parent)
{
init();
}
@@ -103,7 +103,7 @@ protected:
emit Base::attachedToEngine(engine);
}
- QMutex m_configMutex;
+ QRecursiveMutex m_configMutex;
QList<QJSEngine *> m_waitingEngines;
bool m_waitingForConfiguration;
};
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 41bc9fd140..2e8102bd65 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -471,7 +471,7 @@ will be accessible to the \e attachee:
class MessageBoardAttachedType : public QObject
{
Q_OBJECT
- Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
+ Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged)
public:
MessageBoardAttachedType(QObject *parent);
bool expired() const;
@@ -493,7 +493,7 @@ class MessageBoard : public QObject
{
Q_OBJECT
public:
- static MessageBoard *qmlAttachedProperties(QObject *object)
+ static MessageBoardAttachedType *qmlAttachedProperties(QObject *object)
{
return new MessageBoardAttachedType(object);
}
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index ab54b5fd1d..9c106558fd 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -487,8 +487,7 @@
A QObject singleton type may be referenced via the type name with which it was registered, and this
typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
- One exception to this is that a QObject singleton type property may not be aliased (because the
- singleton type name does not identify an object within the same component as any other item).
+ One exception to this is that a QObject singleton type property may not be aliased.
\b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
@@ -619,6 +618,100 @@
*/
/*!
+ \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int
+ versionMinor, const char *typeName, QObject* cppObject)
+ \relates QQmlEngine
+ \since 5.14
+
+ This function is used to register a singleton object \a cppObject, with a
+ particular \a uri and \a typeName. Its version is a combination of \a
+ versionMajor and \a versionMinor.
+
+ Installing a singleton type into a URI allows you to provide arbitrary
+ functionality (methods and properties) to QML code without requiring
+ individual instances of the type to be instantiated by the client.
+
+ Use this function to register an object of the given type T as a singleton
+ type.
+
+ A QObject singleton type may be referenced via the type name with which it
+ was registered; in turn this type name may be used as the target in a \l
+ Connections type, or like any other type ID. However, there's one
+ exception: a QObject singleton type property can't be aliased because the
+ singleton type name does not identify an object within the same component
+ as any other item.
+
+ \note \a cppObject must outlive the QML engine in which it is used.
+ Moreover, \cppObject must have the same thread affinity as the engine. If
+ you want separate singleton instances for multiple engines, you need to use
+ \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
+ information about thread safety.
+
+ Usage:
+ \code
+ // First, define your QObject which provides the functionality.
+ class SingletonTypeExample : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
+
+ public:
+ explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
+
+ Q_INVOKABLE int doSomething()
+ {
+ setSomeProperty(5);
+ return m_someProperty;
+ }
+
+ int someProperty() const { return m_someProperty; }
+ void setSomeProperty(int val) {
+ if (m_someProperty != val) {
+ m_someProperty = val;
+ emit somePropertyChanged(val);
+ }
+ }
+
+ signals:
+ void somePropertyChanged(int newValue);
+
+ private:
+ int m_someProperty = 0;
+ };
+ \endcode
+
+ \code
+ // Second, create an instance of the object
+
+ // allocate example before the engine to ensure that it outlives it
+ QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
+ QQmlEngine engine;
+
+ // Third, register the singleton type provider with QML by calling this
+ // function in an initialization function.
+ qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
+ \endcode
+
+
+ In order to use the registered singleton type in QML, you must import the
+ URI with the corresponding version.
+ \qml
+ import QtQuick 2.0
+ import Qt.example.qobjectSingleton 1.0
+ Item {
+ id: root
+ property int someValue: MyApi.someProperty
+
+ Component.onCompleted: {
+ console.log(MyApi.doSomething())
+ }
+ }
+ \endqml
+
+ \sa qmlRegisterSingletonType
+ */
+
+/*!
\fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
\relates QQmlEngine
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index a5ad6af4a2..e607666886 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -128,6 +128,9 @@ loops - it could indicate that the binding is being used for more than describin
property relationships. Complex bindings can reduce code performance, readability,
and maintainability. It may be a good idea to redesign components that have
complex bindings, or at least factor the binding out into a separate function.
+As a general rule, users should not rely on the evaluation order of bindings.
+
+\sa {Positioning with Anchors}
\target qml-javascript-assignment
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index a77d710cff..164a70d000 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -74,7 +74,7 @@ public:
static const QJSEnginePrivate* get(const QJSEngine*e) { return e->d_func(); }
static QJSEnginePrivate* get(QV4::ExecutionEngine *e);
- QJSEnginePrivate() : mutex(QMutex::Recursive) {}
+ QJSEnginePrivate() = default;
~QJSEnginePrivate() override;
static void addToDebugServer(QJSEngine *q);
@@ -105,7 +105,7 @@ public:
};
// Shared by QQmlEngine
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
// These methods may be called from the QML loader thread
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 1b26608bf3..bba88e5c9a 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -54,7 +54,7 @@
#include <wtf/MathExtras.h>
-#if defined(Q_OS_LINUX) && QT_CONFIG(timezone)
+#if defined(Q_OS_LINUX) && QT_CONFIG(timezone) && !defined(Q_OS_ANDROID)
/*
See QTBUG-56899. Although we don't (yet) have a proper way to reset the
system zone, the code below, that uses QTimeZone::systemTimeZone(), works
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index c836d121e3..7ee6f39aa2 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -147,9 +147,7 @@ bool ExecutableAllocator::ChunkOfPages::contains(Allocation *alloc) const
}
ExecutableAllocator::ExecutableAllocator()
- : mutex(QMutex::NonRecursive)
-{
-}
+ = default;
ExecutableAllocator::~ExecutableAllocator()
{
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 013c6d7120..f98f2c7d33 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -130,7 +130,7 @@ public:
private:
QMultiMap<size_t, Allocation*> freeAllocations;
QMap<quintptr, ChunkOfPages*> chunks;
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
};
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index a9283cfa54..950e0b10ea 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -694,7 +694,7 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt
}
return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
- [this, &unitUrl, errorString](const char *data, quint32 size) {
+ [&unitUrl, errorString](const char *data, quint32 size) {
return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
size, errorString);
});
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index b32e227b58..27075e96a0 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -86,6 +86,7 @@ namespace QV4 {
namespace Promise {
const int PROMISE_REACTION_EVENT = QEvent::registerEventType();
+const int PROMISE_RESOLVE_THENABLE_EVENT = QEvent::registerEventType();
struct ReactionEvent : public QEvent
{
@@ -99,6 +100,18 @@ struct ReactionEvent : public QEvent
QV4::PersistentValue resolution;
};
+struct ResolveThenableEvent : public QEvent
+{
+ ResolveThenableEvent(ExecutionEngine *e, const PromiseObject *promise_, const Object *thenable_, const FunctionObject *then_)
+ : QEvent(QEvent::Type(PROMISE_RESOLVE_THENABLE_EVENT)), promise(e, *promise_), thenable(e, *thenable_), then(e, *then_)
+ {}
+
+ QV4::PersistentValue promise;
+ QV4::PersistentValue thenable;
+ QV4::PersistentValue then;
+};
+
+
} // namespace Promise
} // namespace QV4
QT_END_NAMESPACE
@@ -115,6 +128,11 @@ void ReactionHandler::addReaction(ExecutionEngine *e, const Value *reaction, con
QCoreApplication::postEvent(this, new ReactionEvent(e, reaction, value));
}
+void ReactionHandler::addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then)
+{
+ QCoreApplication::postEvent(this, new ResolveThenableEvent(e, promise, thenable, then));
+}
+
void ReactionHandler::customEvent(QEvent *event)
{
if (event)
@@ -122,6 +140,9 @@ void ReactionHandler::customEvent(QEvent *event)
const int type = event->type();
if (type == PROMISE_REACTION_EVENT)
executeReaction(static_cast<ReactionEvent*>(event));
+
+ if (type == PROMISE_RESOLVE_THENABLE_EVENT)
+ executeResolveThenable(static_cast<ResolveThenableEvent*>(event));
}
}
@@ -159,6 +180,7 @@ void ReactionHandler::executeReaction(ReactionEvent *event)
}
}
+
namespace {
class FunctionBuilder {
@@ -200,6 +222,26 @@ public:
}
+
+void ReactionHandler::executeResolveThenable(ResolveThenableEvent *event)
+{
+ Scope scope(event->then.engine());
+ JSCallData jsCallData(scope, 2);
+ PromiseObject *promise = event->promise.as<PromiseObject>();
+ ScopedFunctionObject resolve {scope, FunctionBuilder::makeResolveFunction(scope.engine, promise->d())};
+ ScopedFunctionObject reject {scope, FunctionBuilder::makeRejectFunction(scope.engine, promise->d())};
+ jsCallData->args[0] = resolve;
+ jsCallData.args[1] = reject;
+ jsCallData->thisObject = event->thenable.as<QV4::Object>();
+ event->then.as<const FunctionObject>()->call(jsCallData);
+ if (scope.engine->hasException) {
+ JSCallData rejectCallData(scope, 1);
+ rejectCallData->args[0] = scope.engine->catchException();
+ Scoped<RejectWrapper> reject {scope, scope.engine->memoryManager->allocate<QV4::RejectWrapper>()};
+ reject->call(rejectCallData);
+ }
+}
+
void Heap::PromiseObject::setState(PromiseObject::State state)
{
this->state = state;
@@ -363,23 +405,36 @@ void Heap::RejectWrapper::init()
Heap::FunctionObject::init();
}
+ReturnedValue PromiseCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
+{
+ // 25.4.3.1 Promise ( executor )
+ // 1. If NewTarget is undefined, throw a TypeError exception.
+ Scope scope(f);
+ THROW_TYPE_ERROR();
+}
ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
+ // 25.4.3.1 Promise ( executor )
+
Scope scope(f);
- if (argc != 1)
+ if (argc == 0) // If there are no arguments, argument 1 will be undefined ==> thus not callable ==> type error
THROW_TYPE_ERROR();
ScopedFunctionObject executor(scope, argv[0].as<const FunctionObject>());
- if (!executor)
- THROW_TYPE_ERROR();
+ if (!executor) //2. If IsCallable(executor) is false
+ THROW_TYPE_ERROR(); // throw a TypeError exception
Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
if (scope.engine->hasException)
return Encode::undefined();
- a->d()->state = Heap::PromiseObject::Pending;
+ a->d()->state = Heap::PromiseObject::Pending; //4. Set promise.[[PromiseState]] to "pending"
+ // 5. Set promise.[[PromiseFulfillReactions]] to a new empty List.
+ // 6. Set promise.[[PromiseRejectReactions]] to a new empty List.
+ // 7. Set promise.[[PromiseIsHandled]] to false.
+ // happens in constructor of a
ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
@@ -387,13 +442,15 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
JSCallData jsCallData(scope, 2);
jsCallData->args[0] = resolve;
jsCallData->args[1] = reject;
- jsCallData->thisObject = a;
+ //jsCallData->thisObject = a; VERIFY corretness, but this should be undefined (see below)
- executor->call(jsCallData);
+ executor->call(jsCallData); // 9. Let completion be Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »).
if (scope.engine->hasException) {
- a->d()->state = Heap::PromiseObject::Rejected;
- a->d()->resolution.set(scope.engine, Value::fromReturnedValue(scope.engine->catchException()));
+ ScopedValue exception {scope, scope.engine->catchException()};
+ JSCallData callData {scope, 1};
+ callData.args[0] = exception;
+ reject->call(callData);
}
if (newTarget)
@@ -402,42 +459,42 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
return a->asReturnedValue();
}
-ReturnedValue PromiseCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
-{
- Scope scope(f);
- THROW_TYPE_ERROR();
-}
ReturnedValue PromiseCtor::method_resolve(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.4.5Promise.resolve ( x )
Scope scope(f);
ExecutionEngine* e = scope.engine;
- if (!thisObject || !thisObject->isObject())
+ if (!thisObject || !thisObject->isObject()) // 2. If Type(C) is not Object, throw a TypeError exception
THROW_TYPE_ERROR();
- ScopedValue argument(scope);
+ ScopedValue x(scope);
if (argc < 1) {
- argument = Encode::undefined();
+ x = Encode::undefined();
} else {
- argument = argv[0];
+ x = argv[0];
}
- if (isPromise(argument) && argument->isObject()) {
+ // 3. If IsPromise(x) is true, then
+ if (isPromise(x) && x->isObject()) {
ScopedObject so(scope, thisObject);
- ScopedObject constructor(scope, argument->objectValue()->get(e->id_constructor()));
- if (so->d() == constructor->d())
- return argument->asReturnedValue();
+ // Let xConstructor be ? Get(x, "constructor").
+ ScopedObject constructor(scope, x->objectValue()->get(e->id_constructor()));
+ if (so->d() == constructor->d()) // If SameValue(xConstructor, C) is true, return x.
+ return x->asReturnedValue();
}
+ // Let promiseCapability be ? NewPromiseCapability(C).
Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
THROW_TYPE_ERROR();
+ // Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
ScopedValue undefined(scope, Value::undefinedValue());
ScopedFunctionObject resolve(scope, capability->d()->resolve);
- resolve->call(undefined, argument, 1);
+ resolve->call(undefined, x, 1);
return newPromise.asReturnedValue();
}
@@ -447,16 +504,18 @@ ReturnedValue PromiseCtor::method_reject(const FunctionObject *f, const Value *t
Scope scope(f);
ExecutionEngine *e = scope.engine;
+ // 2. If Type(C) is not Object, throw a TypeError exception.
if (!thisObject || !thisObject->isObject())
THROW_TYPE_ERROR();
- ScopedValue argument(scope);
+ ScopedValue r(scope);
if (argc < 1) {
- argument = Encode::undefined();
+ r = Encode::undefined();
} else {
- argument = argv[0];
+ r = argv[0];
}
+ // 3. Let promiseCapability be ? NewPromiseCapability(C).
Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
@@ -465,7 +524,8 @@ ReturnedValue PromiseCtor::method_reject(const FunctionObject *f, const Value *t
ScopedValue undefined(scope, Value::undefinedValue());
ScopedFunctionObject reject(scope, capability->d()->reject.as<const FunctionObject>());
- reject->call(undefined, argument, 1);
+ // Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
+ reject->call(undefined, r, 1);
return newPromise.asReturnedValue();
}
@@ -475,6 +535,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
Scope scope(f);
ExecutionEngine* e = scope.engine;
+ // 2. If Type(C) is not Object, throw a TypeError exception.
if (!thisObject || !thisObject->isObject())
THROW_TYPE_ERROR();
@@ -777,6 +838,7 @@ void PromisePrototype::init(ExecutionEngine *engine, Object *ctor)
ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.5.3 Promise.prototype.then
Scope scope(f);
ExecutionEngine* e = scope.engine;
@@ -804,6 +866,7 @@ ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value
if (!constructor || scope.hasException())
THROW_TYPE_ERROR();
+ // 4. Let resultCapability be ? NewPromiseCapability(C).
ScopedObject nextPromise(scope, e->newPromiseObject(constructor, capability));
capability->d()->promise.set(scope.engine, nextPromise);
@@ -811,21 +874,25 @@ ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value
Scoped<PromiseReaction> rejectReaction(scope, Heap::PromiseReaction::createRejectReaction(scope.engine, capability, onRejected));
ScopedValue resolution(scope, promise->d()->resolution);
- if (promise->d()->isPending()) {
+ if (promise->d()->isPending()) { // 7. If promise.[[PromiseState]] is "pending"
{
+ // Append fulfillReaction as the last element of the List that is promise.[[PromiseFulfillReactions]].
ScopedArrayObject a(scope, promise->d()->fulfillReactions);
ScopedValue newValue(scope, fulfillReaction->d());
a->push_back(newValue);
}
{
+ // Append rejectReaction as the last element of the List that is promise.[[PromiseRejectReactions]].
ScopedArrayObject a(scope, promise->d()->rejectReactions);
ScopedValue newValue(scope, rejectReaction->d());
a->push_back(newValue);
}
- } else if (promise->d()->isFulfilled()) {
- fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
- } else if (promise->d()->isRejected()) {
+ } else if (promise->d()->isFulfilled()) { // 8. Else if promise.[[PromiseState]] is "fulfilled", then
+ // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « fulfillReaction, value »).
+ fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution); // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « fulfillReaction, value »).
+ } else if (promise->d()->isRejected()) { // 9. Else
+ // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « rejectReaction, reason »).
rejectReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
} else {
Q_ASSERT(false);
@@ -889,7 +956,6 @@ ReturnedValue CapabilitiesExecutorWrapper::virtualCall(const FunctionObject *f,
if (argc >= 2 && !argv[1].isUndefined())
capabilities->reject.set(scope.engine, argv[1]);
- // TODO: return?
return Encode::undefined();
}
@@ -929,27 +995,60 @@ ReturnedValue ResolveElementWrapper::virtualCall(const FunctionObject *f, const
ReturnedValue ResolveWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.1.3.2 (ecmase-262/8.0)
+
Q_UNUSED(thisObject);
Scope scope(f);
const ResolveWrapper *self = static_cast<const ResolveWrapper*>(f);
Scoped<PromiseObject> promise(scope, self->d()->promise);
- if (self->d()->alreadyResolved || !promise->d()->isPending())
+ // 4. If alreadyRseolved.[[Value]] is true, return undefined
+ if (self->d()->alreadyResolved || !promise->d()->isPending()) // Why check for pending?
return Encode::undefined();
- ScopedValue value(scope);
+ // 5. Set alreadyResolved.[[Value]] to true
+ self->d()->alreadyResolved = true;
+
+ ScopedValue resolution(scope);
if (argc == 1) {
- value = argv[0];
+ resolution = argv[0];
} else {
- value = Encode::undefined();
+ resolution = Encode::undefined();
}
- self->d()->alreadyResolved = true;
- promise->d()->setState(Heap::PromiseObject::Fulfilled);
- promise->d()->resolution.set(scope.engine, value);
-
- promise->d()->triggerFullfillReactions(scope.engine);
+ if (!resolution->isObject()) { // 7 If Type(resolution) is not Object
+ // then Return FullFillPromise(promise, resolution)
+ // (FullFillPromise will return undefined, so we share the return with the other path which also returns undefined
+ promise->d()->setState(Heap::PromiseObject::Fulfilled);
+ promise->d()->resolution.set(scope.engine, resolution);
+ promise->d()->triggerFullfillReactions(scope.engine);
+ } else {
+ //PromiseObject *promise = resolution->as<PromiseObject>();
+ auto resolutionObject = resolution->as<Object>();
+ ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("then")));
+
+ // 8. Let then be Get(resolution, then)
+ ScopedFunctionObject thenAction { scope, resolutionObject->get(thenName)};
+ // 9. If then is an abrupt completion, then
+ if (scope.engine->hasException) {
+ // Return RecjectPromise(promise, then.[[Value]]
+ ScopedValue thenValue {scope, scope.engine->catchException()};
+ promise->d()->setState(Heap::PromiseObject::Rejected);
+ promise->d()->resolution.set(scope.engine, thenValue);
+ promise->d()->triggerRejectReactions(scope.engine);
+ } else {
+ // 10. Let thenAction be then.[[Value]]
+ if (!thenAction) { // 11. If IsCallable(thenAction) is false
+ promise->d()->setState(Heap::PromiseObject::Fulfilled);
+ promise->d()->resolution.set(scope.engine, resolution);
+ promise->d()->triggerFullfillReactions(scope.engine);
+ } else {
+ // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, « promise, resolution, thenAction »).
+ scope.engine->getPromiseReactionHandler()->addResolveThenable(scope.engine, promise.getPointer(), resolutionObject, thenAction);
+ }
+ }
+ }
return Encode::undefined();
}
@@ -972,11 +1071,25 @@ ReturnedValue RejectWrapper::virtualCall(const FunctionObject *f, const Value *t
value = Encode::undefined();
}
- self->d()->alreadyResolved = true;
- promise->d()->setState(Heap::PromiseObject::Rejected);
- promise->d()->resolution.set(scope.engine, value);
+ if (!isPromise(value)) {
+ self->d()->alreadyResolved = true;
+ promise->d()->setState(Heap::PromiseObject::Rejected);
+ promise->d()->resolution.set(scope.engine, value);
+
+ promise->d()->triggerRejectReactions(scope.engine);
- promise->d()->triggerRejectReactions(scope.engine);
+ } else {
+ PromiseObject *promise = value->as<PromiseObject>();
+ ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("catch")));
+
+ ScopedFunctionObject then(scope, promise->get(thenName));
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = *f;
+ jsCallData->args[1] = Encode::undefined();
+ jsCallData->thisObject = value;
+
+ then->call(jsCallData);
+ }
return Encode::undefined();
}
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index bce59b19a7..8a3724e07d 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -62,6 +62,7 @@ struct PromiseCapability;
namespace Promise {
struct ReactionEvent;
+struct ResolveThenableEvent;
class ReactionHandler : public QObject
{
@@ -69,13 +70,15 @@ class ReactionHandler : public QObject
public:
ReactionHandler(QObject *parent = nullptr);
- virtual ~ReactionHandler();
+ virtual ~ReactionHandler() override;
void addReaction(ExecutionEngine *e, const Value *reaction, const Value *value);
+ void addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then);
protected:
- void customEvent(QEvent *event);
+ void customEvent(QEvent *event) override;
void executeReaction(ReactionEvent *event);
+ void executeResolveThenable(ResolveThenableEvent *event);
};
} // Promise
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 82b040232a..6c9760e472 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1396,6 +1396,14 @@ UiObjectMember: FunctionDeclarationWithTypes;
} break;
./
+UiObjectMember: GeneratorExpression;
+/.
+ case $rule_number: {
+ auto node = new (pool) AST::UiSourceElement(sym(1).Node);
+ sym(1).Node = node;
+ } break;
+./
+
UiObjectMember: VariableStatement;
/.
case $rule_number: {
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 1502298d14..39194068bf 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -3351,7 +3351,7 @@ public:
SourceLocation firstSourceLocation() const override
{
- if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->firstSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->firstSourceLocation();
@@ -3361,7 +3361,7 @@ public:
SourceLocation lastSourceLocation() const override
{
- if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->lastSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->lastSourceLocation();
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 613816e3f7..8a50b51b5d 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -76,6 +76,26 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q
return QQmlMetaType::typeId(uri, versionMajor, versionMinor, qmlName);
}
+// From qqmlprivate.h
+QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (qeng->thread() != m_object->thread()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+ if (alreadyCalled) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+ alreadyCalled = true;
+ qeng->setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ return m_object;
+};
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 4f3bfb76b0..bfd1c88b28 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -667,6 +667,15 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+template<typename T>
+inline auto qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor,
+ const char *typeName, T *cppObject) -> typename std::enable_if<std::is_base_of<QObject, T>::value, int>::type
+{
+ QQmlPrivate::RegisterSingletonFunctor registrationFunctor;
+ registrationFunctor.m_object = cppObject;
+ return qmlRegisterSingletonType<T>(uri, versionMajor, versionMinor, typeName, registrationFunctor);
+}
+
inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
if (url.isRelative()) {
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 7ba5fc08a5..0580efe0d2 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -2454,17 +2454,20 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
if (!o) {
- qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
- qPrintable(QString::fromUtf8(type.typeName())));
+ QQmlError error;
+ error.setMessageType(QtMsgType::QtCriticalMsg);
+ error.setDescription(QString::asprintf("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
+ qPrintable(QString::fromUtf8(type.typeName()))));
+ warning(error);
+ } else {
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(q, o);
}
- // if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(q, o);
// even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
value = q->newQObject(o);
singletonInstances.insert(type, value);
-
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
QObject *o = component.beginCreate(q->rootContext());
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 739d5ce4cd..0b94ed3b49 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qqmlerror.h"
+#include "qqmlfile.h"
#include "qqmlsourcecoordinate_p.h"
#include <private/qqmljsdiagnosticmessage_p.h>
@@ -307,8 +308,8 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
QUrl url = error.url();
- if (error.line() > 0 && url.scheme() == QLatin1String("file")) {
- QString file = url.toLocalFile();
+ if (error.line() > 0 && (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc"))) {
+ QString file = QQmlFile::urlToLocalFileOrQrc(url);
QFile f(file);
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index f4cdb45aff..7c9c0da01a 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -395,9 +395,18 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
const QQmlDirComponents &components = import->qmlDirComponents;
+ const int importMajorVersion = import->majversion;
+ const int importMinorVersion = import->minversion;
+ auto shouldSkipSingleton = [importMajorVersion, importMinorVersion](int singletonMajorVersion, int singletonMinorVersion) -> bool {
+ return importMajorVersion != -1 &&
+ (singletonMajorVersion > importMajorVersion || (singletonMajorVersion == importMajorVersion && singletonMinorVersion > importMinorVersion));
+ };
+
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
+ if (shouldSkipSingleton(cit->majorVersion, cit->minorVersion))
+ continue;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = cit->typeName;
ref.prefix = set.prefix;
@@ -408,7 +417,9 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
}
if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
- module->walkCompositeSingletons([&resultList, &set](const QQmlType &singleton) {
+ module->walkCompositeSingletons([&resultList, &set, &shouldSkipSingleton](const QQmlType &singleton) {
+ if (shouldSkipSingleton(singleton.majorVersion(), singleton.minorVersion()))
+ return;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = singleton.elementName();
ref.prefix = set.prefix;
@@ -1947,7 +1958,9 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::setImportPathList: " << paths;
- fileImportPath = paths;
+ fileImportPath.clear();
+ for (auto it = paths.crbegin(); it != paths.crend(); ++it)
+ addImportPath(*it);
// Our existing cached paths may have been invalidated
clearDirCache();
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index f21427ff69..2c641d3845 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -60,7 +60,7 @@ struct LockedData : private QQmlMetaTypeData
};
Q_GLOBAL_STATIC(LockedData, metaTypeData)
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, metaTypeDataLock, (QMutex::Recursive))
+Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
class QQmlMetaTypeDataPtr
{
@@ -804,7 +804,7 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
return QQmlType();
}
-QMutex *QQmlMetaType::typeRegistrationLock()
+QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
{
return metaTypeDataLock();
}
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index c2535a7fd5..6c2b0bb2a6 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
class QQmlTypeModule;
-class QMutex;
+class QRecursiveMutex;
class QQmlError;
namespace QV4 { class ExecutableCompilationUnit; }
@@ -160,7 +160,7 @@ public:
static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
- static QMutex *typeRegistrationLock();
+ static QRecursiveMutex *typeRegistrationLock();
static QString prettyTypeName(const QObject *object);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index d5681b3449..f89608cd5d 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -57,6 +57,7 @@
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmlscriptdata_p.h>
#include <private/qjsvalue_p.h>
+#include <private/qv4generatorobject_p.h>
#include <qtqml_tracepoints_p.h>
@@ -1135,7 +1136,10 @@ void QQmlObjectCreator::setupFunctions()
if (!property->isVMEFunction())
continue;
- function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
+ if (runtimeFunction->isGenerator())
+ function = QV4::GeneratorFunction::create(qmlContext, runtimeFunction);
+ else
+ function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
_vmeMetaObject->setVmeMethod(property->coreIndex(), function);
}
}
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index eff78195d9..e6dd5e0b16 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -322,6 +322,13 @@ namespace QQmlPrivate
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
+ struct Q_QML_EXPORT RegisterSingletonFunctor
+ {
+ QObject *operator()(QQmlEngine *, QJSEngine *);
+
+ QObject *m_object;
+ bool alreadyCalled = false;
+ };
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index c8166695ba..5f57e0eca1 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1216,10 +1216,18 @@ bool QQmlPropertyPrivate::write(QObject *object,
if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
} else if (property.isQObject()) {
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, variantType);
+ QVariant val = value;
+ int varType = variantType;
+ if (variantType == QMetaType::Nullptr) {
+ // This reflects the fact that you can assign a nullptr to a QObject pointer
+ // Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
+ varType = QMetaType::QObjectStar;
+ val = QVariant(QMetaType::QObjectStar, nullptr);
+ }
+ QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType);
if (valMo.isNull())
return false;
- QObject *o = *static_cast<QObject *const *>(value.constData());
+ QObject *o = *static_cast<QObject *const *>(val.constData());
QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
if (o)
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index b435f8ef66..4db0562c0e 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1570,7 +1570,8 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
+ QQmlEnginePrivate *qmlEnginePrivate = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr;
+ QQmlEnginePrivate::warning(qmlEnginePrivate, error);
}
};
@@ -1761,8 +1762,13 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
// Argument 1 - URL
QUrl url = QUrl(argv[1].toQStringNoThrow());
- if (url.isRelative())
- url = scope.engine->callingQmlContext()->resolvedUrl(url);
+ if (url.isRelative()) {
+ QQmlContextData *qmlContextData = scope.engine->callingQmlContext();
+ if (qmlContextData)
+ url = qmlContextData->resolvedUrl(url);
+ else
+ url = scope.engine->resolvedUrl(url.url());
+ }
bool async = true;
// Argument 2 - async (optional)
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 5067b6a02e..4b60108597 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -70,12 +70,8 @@ public:
, delayed(false)
, pendingEval(false)
, restoreBinding(true)
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
, restoreValue(false)
, restoreModeExplicit(false)
-#else
- , restoreValue(true)
-#endif
{}
~QQmlBindPrivate() { }
@@ -93,9 +89,7 @@ public:
bool pendingEval:1;
bool restoreBinding:1;
bool restoreValue:1;
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
bool restoreModeExplicit:1;
-#endif
void validate(QObject *binding) const;
void clearPrev();
@@ -365,8 +359,7 @@ void QQmlBind::setDelayed(bool delayed)
\li Binding.RestoreBindingOrValue The original value is always restored.
\list
- \warning The default value is Binding.RestoreBinding. This will change in
- Qt 5.15 to Binding.RestoreBindingOrValue.
+ The default value is Binding.RestoreBinding.
If you rely on any specific behavior regarding the restoration of plain
values when bindings get disabled you should migrate to explicitly set the
@@ -392,9 +385,7 @@ void QQmlBind::setRestoreMode(RestorationMode newMode)
if (newMode != restoreMode()) {
d->restoreValue = (newMode & RestoreValue);
d->restoreBinding = (newMode & RestoreBinding);
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
d->restoreModeExplicit = true;
-#endif
emit restoreModeChanged();
}
}
@@ -465,27 +456,11 @@ void QQmlBind::eval()
Q_ASSERT(vmemo);
vmemo->setVMEProperty(propPriv->core.coreIndex(), *d->v4Value.valueRef());
d->clearPrev();
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
- } else if (!d->restoreModeExplicit) {
- qmlWarning(this)
- << "Not restoring previous value because restoreMode has not been set."
- << "This behavior is deprecated."
- << "In Qt < 5.15 the default is Binding.RestoreBinding."
- << "In Qt >= 5.15 the default is Binding.RestoreBindingOrValue.";
-#endif
}
} else if (d->prevIsVariant) {
if (d->restoreValue) {
d->prop.write(d->prevValue);
d->clearPrev();
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
- } else if (!d->restoreModeExplicit) {
- qmlWarning(this)
- << "Not restoring previous value because restoreMode has not been set."
- << "This behavior is deprecated."
- << "In Qt < 5.15 the default is Binding.RestoreBinding."
- << "In Qt >= 5.15 the default is Binding.RestoreBindingOrValue.";
-#endif
}
}
return;