diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-06-24 14:40:02 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-07-11 13:37:26 +0200 |
commit | e19328fb0fefdf60a111bb662bf6ce0df901ac8f (patch) | |
tree | 8cdba6417ea5ab575e41f4c44bcbb5b5aca2d479 /src | |
parent | 989e05a0b8240778c9f249edea5c9d27d68f8e0f (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.cpp | 58 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 26 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 19 |
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) |