aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-06-24 14:40:02 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-07-11 13:37:26 +0200
commite19328fb0fefdf60a111bb662bf6ce0df901ac8f (patch)
tree8cdba6417ea5ab575e41f4c44bcbb5b5aca2d479 /src
parent989e05a0b8240778c9f249edea5c9d27d68f8e0f (diff)
QmlCompiler: Allow storeNameSloppy to reset a property
We should not convert from undefined on storeNameSloppy. The reset is intentional. Task-number: QTBUG-104508 Change-Id: Iede88fe6331dd173c9e8ea0ec4200df2b8bd30eb Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqml.cpp58
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp26
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp19
3 files changed, 76 insertions, 27 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 0fd0f9b5cd..847522f052 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -862,7 +862,8 @@ static ObjectPropertyResult loadFallbackProperty(
return ObjectPropertyResult::OK;
}
-static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+template<typename Op>
+static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
{
const QQmlData *qmlData = QQmlData::get(object);
if (!qmlData)
@@ -874,11 +875,26 @@ static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object,
return ObjectPropertyResult::NeedsInit;
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
- property->writeProperty(object, value, {});
+ op(property);
return ObjectPropertyResult::OK;
}
-static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+static ObjectPropertyResult resetObjectProperty(QV4::Lookup *l, QObject *object)
+{
+ return changeObjectProperty(l, object, [&](const QQmlPropertyData *property) {
+ property->resetProperty(object, {});
+ });
+}
+
+static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeObjectProperty(l, object, [&](const QQmlPropertyData *property) {
+ property->writeProperty(object, value, {});
+ });
+}
+
+template<typename Op>
+static ObjectPropertyResult changeFallbackProperty(QV4::Lookup *l, QObject *object, Op op)
{
const QQmlData *qmlData = QQmlData::get(object);
if (qmlData && qmlData->isQueuedForDeletion)
@@ -893,11 +909,26 @@ static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *objec
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
- void *args[] = { value, nullptr };
- metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ op(metaObject, coreIndex);
return ObjectPropertyResult::OK;
}
+static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ void *args[] = { value, nullptr };
+ metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ });
+}
+
+static ObjectPropertyResult resetFallbackProperty(QV4::Lookup *l, QObject *object)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ void *args[] = { nullptr };
+ metaObject->metacall(object, QMetaObject::ResetProperty, coreIndex, args);
+ });
+}
+
static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
{
if (!lookupType.isValid()) {
@@ -1115,6 +1146,19 @@ QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
return QMetaType();
}
+static bool isUndefined(const void *value, QMetaType type)
+{
+ if (type == QMetaType::fromType<QVariant>())
+ return !static_cast<const QVariant *>(value)->isValid();
+ if (type == QMetaType::fromType<QJSValue>())
+ return static_cast<const QJSValue *>(value)->isUndefined();
+ if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
+ return static_cast<const QJSPrimitiveValue *>(value)->type()
+ == QJSPrimitiveValue::Undefined;
+ }
+ return false;
+}
+
void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType type) const
{
// We don't really use any part of the lookup machinery here.
@@ -1130,6 +1174,8 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
const QMetaType propType = l.qobjectLookup.propertyData->propType();
if (type == propType) {
storeResult = storeObjectProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetObjectProperty(&l, qmlScopeObject);
} else {
QVariant var(propType);
propType.convert(type, value, propType, var.data());
@@ -1146,6 +1192,8 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
= metaObject->property(l.qobjectFallbackLookup.coreIndex).metaType();
if (type == propType) {
storeResult = storeFallbackProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetFallbackProperty(&l, qmlScopeObject);
} else {
QVariant var(propType);
propType.convert(type, value, propType, var.data());
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 5369c09681..3e29cbc916 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -610,24 +610,14 @@ void QQmlJSCodeGenerator::generate_StoreNameSloppy(int nameIndex)
switch (type.variant()) {
case QQmlJSRegisterContent::ScopeProperty:
case QQmlJSRegisterContent::ExtensionScopeProperty: {
- if (!m_typeResolver->registerContains(m_state.accumulatorIn(), type.property().type())) {
- m_body += u"{\n"_s;
- m_body += u"auto converted = "_s
- + conversion(m_state.accumulatorIn(), type, m_state.accumulatorVariableIn)
- + u";\n"_s;
- m_body += u"aotContext->storeNameSloppy("_s + QString::number(nameIndex)
- + u", "_s + contentPointer(type, u"converted"_s)
- + u", "_s + contentType(type, u"converted"_s) + u')';
- m_body += u";\n"_s;
- m_body += u"}\n"_s;
- } else {
- m_body += u"aotContext->storeNameSloppy("_s + QString::number(nameIndex)
- + u", "_s
- + contentPointer(m_state.accumulatorIn(), m_state.accumulatorVariableIn)
- + u", "_s
- + contentType(m_state.accumulatorIn(), m_state.accumulatorVariableIn) + u')';
- m_body += u";\n"_s;
- }
+ // Do not convert here. We may intentionally pass the "wrong" type, for example to trigger
+ // a property reset.
+ m_body += u"aotContext->storeNameSloppy("_s + QString::number(nameIndex)
+ + u", "_s
+ + contentPointer(m_state.accumulatorIn(), m_state.accumulatorVariableIn)
+ + u", "_s
+ + contentType(m_state.accumulatorIn(), m_state.accumulatorVariableIn) + u')';
+ m_body += u";\n"_s;
break;
}
case QQmlJSRegisterContent::ScopeMethod:
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 1950e33d92..03a68f33c8 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -584,6 +584,7 @@ void QQmlJSTypePropagator::generate_StoreNameSloppy(int nameIndex)
{
const QString name = m_jsUnitGenerator->stringForIndex(nameIndex);
const QQmlJSRegisterContent type = m_typeResolver->scopedType(m_function->qmlScope, name);
+ const QQmlJSRegisterContent in = m_state.accumulatorIn();
if (!type.isValid()) {
setError(u"Cannot find name "_s + name);
@@ -604,19 +605,29 @@ void QQmlJSTypePropagator::generate_StoreNameSloppy(int nameIndex)
return;
}
- if (!canConvertFromTo(m_state.accumulatorIn(), type)) {
+ if (!canConvertFromTo(in, type)) {
setError(u"cannot convert from %1 to %2"_s
- .arg(m_state.accumulatorIn().descriptiveName(), type.descriptiveName()));
+ .arg(in.descriptiveName(), type.descriptiveName()));
}
if (m_passManager != nullptr) {
m_passManager->analyzeWrite(m_function->qmlScope, name,
- m_typeResolver->containedType(m_state.accumulatorIn()),
+ m_typeResolver->containedType(in),
m_function->qmlScope, getCurrentSourceLocation());
}
m_state.setHasSideEffects(true);
- addReadAccumulator(type);
+
+ if (m_typeResolver->canHoldUndefined(in) && !m_typeResolver->canHoldUndefined(type)) {
+ if (type.property().reset().isEmpty())
+ setError(u"Cannot assign potential undefined to %1"_s.arg(type.descriptiveName()));
+ else if (m_typeResolver->registerIsStoredIn(in, m_typeResolver->voidType()))
+ addReadAccumulator(m_typeResolver->globalType(m_typeResolver->varType()));
+ else
+ addReadAccumulator(in);
+ } else {
+ addReadAccumulator(type);
+ }
}
void QQmlJSTypePropagator::generate_StoreNameStrict(int name)