diff --git a/desktop/toolkit/qt6/qt6-declarative/files/9c6b2b78e9076f1c2676aa0c41573db9ca480654.diff b/desktop/toolkit/qt6/qt6-declarative/files/9c6b2b78e9076f1c2676aa0c41573db9ca480654.diff new file mode 100644 index 0000000000..8f3618e894 --- /dev/null +++ b/desktop/toolkit/qt6/qt6-declarative/files/9c6b2b78e9076f1c2676aa0c41573db9ca480654.diff @@ -0,0 +1,226 @@ +diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h +index 083c3ec2df8..ef36bf67c50 100644 +--- a/src/qml/jsruntime/qv4lookup_p.h ++++ b/src/qml/jsruntime/qv4lookup_p.h +@@ -159,6 +159,10 @@ struct Q_QML_EXPORT Lookup { + const QQmlPropertyData *propertyData; + } qobjectMethodLookup; + struct { ++ // NB: None of this is actually cache-able. The metaobject may change at any time. ++ // We invalidate this data every time the lookup is invoked and thereby force a ++ // re-initialization next time. ++ + quintptr isConstant; // This is a bool, encoded as 0 or 1. Both values are ignored by gc + quintptr metaObject; // a (const QMetaObject* & 1) or nullptr + int coreIndex; +diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp +index 4e3b4fcf1ee..3f0d9e332b1 100644 +--- a/src/qml/qml/qqml.cpp ++++ b/src/qml/qml/qqml.cpp +@@ -1386,16 +1386,16 @@ struct FallbackPropertyQmlData + + static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *lookup, QObject *object) + { ++ // We've just initialized the lookup. So everything must be fine here. ++ + QQmlData *qmlData = QQmlData::get(object); +- if (qmlData && qmlData->isQueuedForDeletion) +- return {qmlData, nullptr, PropertyResult::Deleted}; + ++ Q_ASSERT(!qmlData || !qmlData->isQueuedForDeletion); + Q_ASSERT(!QQmlData::wasDeleted(object)); + + const QMetaObject *metaObject + = reinterpret_cast(lookup->qobjectFallbackLookup.metaObject - 1); +- if (!metaObject || metaObject != object->metaObject()) +- return {qmlData, nullptr, PropertyResult::NeedsInit}; ++ Q_ASSERT(metaObject == object->metaObject()); + + return {qmlData, metaObject, PropertyResult::OK}; + } +@@ -2585,6 +2585,7 @@ bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) + break; + case QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback: + result = loadFallbackProperty(lookup, qmlScopeObject, target, this); ++ lookup->call = QV4::Lookup::Call::ContextGetterGeneric; + break; + default: + return false; +@@ -2616,6 +2617,7 @@ bool AOTCompiledContext::writeBackScopeObjectPropertyLookup(uint index, void *so + break; + case QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback: + result = writeBackFallbackProperty(lookup, qmlScopeObject, source); ++ lookup->call = QV4::Lookup::Call::ContextGetterGeneric; + break; + default: + return false; +@@ -2816,6 +2818,7 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ + result = lookup->asVariant + ? loadFallbackAsVariant(lookup, object, target, this) + : loadFallbackProperty(lookup, object, target, this); ++ lookup->call = QV4::Lookup::Call::GetterGeneric; + break; + default: + return false; +@@ -2850,6 +2853,7 @@ bool AOTCompiledContext::writeBackObjectLookup(uint index, QObject *object, void + result = lookup->asVariant + ? writeBackFallbackAsVariant(lookup, object, source) + : writeBackFallbackProperty(lookup, object, source); ++ lookup->call = QV4::Lookup::Call::GetterGeneric; + break; + default: + return false; +@@ -3010,6 +3014,7 @@ bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *valu + result = lookup->asVariant + ? storeFallbackAsVariant(engine->handle(), lookup, object, value) + : storeFallbackProperty(lookup, object, value); ++ lookup->call = QV4::Lookup::Call::SetterGeneric; + break; + default: + return false; +diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +index 79e908c9674..67cdefa30d9 100644 +--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt ++++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +@@ -26,6 +26,7 @@ set(cpp_sources + multiforeign.h + objectwithmethod.h + person.cpp person.h ++ propertymap.h + qmlusing.h + recursiveObject.h + refuseWrite.h +@@ -282,6 +283,7 @@ set(qml_files + popContextAfterRet.qml + prefixedMetaType.qml + pressAndHoldButton.qml ++ propertyMap.qml + qmlUsing.qml + qtbug113150.qml + qtfont.qml +diff --git a/tests/auto/qml/qmlcppcodegen/data/propertyMap.qml b/tests/auto/qml/qmlcppcodegen/data/propertyMap.qml +new file mode 100644 +index 00000000000..c00f3972e8a +--- /dev/null ++++ b/tests/auto/qml/qmlcppcodegen/data/propertyMap.qml +@@ -0,0 +1,6 @@ ++pragma Strict ++import TestTypes ++ ++WithPropertyMap { ++ objectName: map.foo ++} +diff --git a/tests/auto/qml/qmlcppcodegen/data/propertymap.h b/tests/auto/qml/qmlcppcodegen/data/propertymap.h +new file mode 100644 +index 00000000000..64d84c5c097 +--- /dev/null ++++ b/tests/auto/qml/qmlcppcodegen/data/propertymap.h +@@ -0,0 +1,40 @@ ++// Copyright (C) 2025 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only ++ ++#ifndef PROPERTYMAP_H ++#define PROPERTYMAP_H ++ ++#include ++#include ++#include ++ ++class WithPropertyMap : public QObject ++{ ++ Q_OBJECT ++ QML_ELEMENT ++ Q_PROPERTY(QQmlPropertyMap *map READ map NOTIFY mapChanged) ++public: ++ WithPropertyMap(QObject *parent = nullptr) ++ : QObject(parent) ++ , m_map(new QQmlPropertyMap(this)) ++ { ++ } ++ ++ QQmlPropertyMap *map() const { return m_map; } ++ ++ void setProperties(const QVariantHash &properties) ++ { ++ delete m_map; ++ m_map = new QQmlPropertyMap(this); ++ m_map->insert(properties); ++ emit mapChanged(); ++ } ++ ++signals: ++ void mapChanged(); ++ ++private: ++ QQmlPropertyMap *m_map = nullptr; ++}; ++ ++#endif // PROPERTYMAP_H +diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +index 70c50b457a9..a90e2a60505 100644 +--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp ++++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -237,6 +238,7 @@ private slots: + void parentProperty(); + void popContextAfterRet(); + void prefixedType(); ++ void propertyMap(); + void propertyOfParent(); + void qmlUsing(); + void qtfont(); +@@ -4908,6 +4910,47 @@ void tst_QmlCppCodegen::prefixedType() + QCOMPARE(o->property("countH").toInt(), 11); + } + ++void tst_QmlCppCodegen::propertyMap() ++{ ++ QQmlEngine engine; ++ ++ const QUrl document(u"qrc:/qt/qml/TestTypes/propertyMap.qml"_s); ++ QQmlComponent c(&engine, document); ++ QVERIFY2(c.isReady(), qPrintable(c.errorString())); ++ ++ QTest::ignoreMessage( ++ QtWarningMsg, qPrintable( ++ document.toString() ++ + u":5:5: QML WithPropertyMap: Unable to assign [undefined] to \"objectName\"")); ++ ++ QScopedPointer o(c.create()); ++ QVERIFY(o); ++ ++ WithPropertyMap *w = qobject_cast(o.data()); ++ QVERIFY(w); ++ ++ QVERIFY(w->objectName().isEmpty()); ++ ++ w->setProperties({ ++ { u"foo"_s, u"aaa"_s }, ++ { u"bar"_s, u"bbb"_s }, ++ }); ++ ++ QCOMPARE(w->objectName(), u"aaa"_s); ++ ++ w->setProperties({ ++ { u"foo"_s, u"ccc"_s }, ++ }); ++ ++ QCOMPARE(w->objectName(), u"ccc"_s); ++ ++ w->setProperties({ ++ { u"foo"_s, 24.25 }, ++ }); ++ ++ QCOMPARE(w->objectName(), u"24.25"_s); ++} ++ + void tst_QmlCppCodegen::propertyOfParent() + { + QQmlEngine engine; diff --git a/desktop/toolkit/qt6/qt6-declarative/pspec.xml b/desktop/toolkit/qt6/qt6-declarative/pspec.xml index b33e99e6d3..85dc352fd7 100755 --- a/desktop/toolkit/qt6/qt6-declarative/pspec.xml +++ b/desktop/toolkit/qt6/qt6-declarative/pspec.xml @@ -29,7 +29,7 @@ qt6-languageserver-devel - + 9c6b2b78e9076f1c2676aa0c41573db9ca480654.diff @@ -74,7 +74,7 @@ - + 2025-11-30 6.10.1 Version bump.