aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-04-03 10:15:07 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-05-02 19:29:25 +0200
commit46cc70e2aafc84db6caeaf747629ee6e825b0a4d (patch)
tree6b599a7754efa2877b15cee918006da5242d5a9f /src/qml
parent961d11e55f3eb1ac2e33eefd80adede01cc62622 (diff)
QmlCompiler: Relax shadowing check
If we detect a property or method as potentially shadowed, we don't have to abandon all hope. We can still retrieve it as untyped var. Since there are a number of things we can do with untyped var, this may still be useful. In the same sense, we need to treat function calls as untyped when the function in question can be shadowed. Calling functions with var arguments and return types leads to some more interesting situations in the call frame setup, so we fix that, too. Task-number: QTBUG-112480 Change-Id: I238d1cf04951f390c73e14ed9e299f2aa72b68cb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp47
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp49
-rw-r--r--src/qml/qml/qqml.cpp158
4 files changed, 233 insertions, 29 deletions
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index abf88f4283..ff6b349ad9 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -201,6 +201,21 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V
return o->get(name);
}
+ReturnedValue Lookup::getterFallbackAsVariant(
+ Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ if (&Lookup::getterFallback == &Lookup::getterFallbackAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This getter just marks the presence of a fallback lookup with variant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return getterFallback(l, engine, object);
+}
+
ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
@@ -401,6 +416,21 @@ ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, con
return QObjectWrapper::lookupPropertyGetterImpl(lookup, engine, object, flags, revertLookup);
}
+ReturnedValue Lookup::getterQObjectAsVariant(
+ Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ if (&Lookup::getterQObject == &Lookup::getterQObjectAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This getter marks the presence of a qobjectlookup with variant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return getterQObject(lookup, engine, object);
+}
+
ReturnedValue Lookup::getterQObjectMethod(Lookup *lookup, ExecutionEngine *engine, const Value &object)
{
const auto revertLookup = [lookup, engine, &object]() {
@@ -559,6 +589,14 @@ bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c
return o->put(name, value);
}
+bool Lookup::setterFallbackAsVariant(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ // This setter just marks the presence of a fallback lookup with QVariant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return setterFallback(l, engine, object, value);
+}
+
bool Lookup::setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -622,6 +660,15 @@ bool Lookup::setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, co
return QV4::Lookup::setterFallback(l, engine, object, v);
}
+bool Lookup::setterQObjectAsVariant(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &v)
+{
+ // This setter marks the presence of a qobjectlookup with QVariant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return QV4::Lookup::setterFallback(l, engine, object, v);
+}
+
+
bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object, const Value &value)
{
Q_ASSERT(object.isObject() && static_cast<Object &>(object).isArrayObject());
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 88a91aacf3..1637d4d82e 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -165,6 +165,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -178,6 +179,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterQObjectMethod(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -192,11 +194,13 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
Q_NEVER_INLINE static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
void markObjects(MarkStack *stack) {
@@ -216,7 +220,9 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
|| getter == QQmlTypeWrapper::lookupSingletonProperty
|| setter == setterQObject
|| qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
- || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty
+ || getter == getterQObjectAsVariant
+ || setter == setterQObjectAsVariant) {
if (const QQmlPropertyCache *pc = qobjectLookup.propertyCache)
pc->release();
} else if (getter == getterQObjectMethod
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index ee7a1ce68e..5e4e93fbd9 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -416,8 +416,11 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
Q_ALLOCA_DECLARE(void *, transformedArguments);
for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ const bool isValid = frame->argc() > i;
+ const QMetaType frameType = isValid ? frame->argTypes()[i] : QMetaType();
+
const QMetaType argumentType = function->typedFunction->argumentTypes[i];
- if (frame->argc() > i && argumentType == frame->argTypes()[i])
+ if (isValid && argumentType == frameType)
continue;
if (transformedArguments == nullptr) {
@@ -430,22 +433,41 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
continue;
}
+ void *frameVal = isValid ? frame->argv()[i] : nullptr;
+ if (isValid && frameType == QMetaType::fromType<QVariant>()) {
+ QVariant *variant = static_cast<QVariant *>(frameVal);
+
+ const QMetaType variantType = variant->metaType();
+ if (variantType == argumentType) {
+ // Slightly nasty, but we're allowed to do this.
+ // We don't want to destruct() the QVariant's data() below.
+ transformedArguments[i] = frame->argv()[i] = variant->data();
+ } else {
+ Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
+ argumentType.construct(arg);
+ QMetaType::convert(variantType, variant->data(), argumentType, arg);
+ transformedArguments[i] = arg;
+ }
+ continue;
+ }
+
Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
if (argumentType == QMetaType::fromType<QVariant>()) {
- if (frame->argc() > i)
- new (arg) QVariant(frame->argTypes()[i], frame->argv()[i]);
+ if (isValid)
+ new (arg) QVariant(frameType, frameVal);
else
new (arg) QVariant();
} else if (argumentType == QMetaType::fromType<QJSPrimitiveValue>()) {
- if (frame->argc() > i)
- new (arg) QJSPrimitiveValue(frame->argTypes()[i], frame->argv()[i]);
+ if (isValid)
+ new (arg) QJSPrimitiveValue(frameType, frameVal);
else
new (arg) QJSPrimitiveValue();
} else {
+
argumentType.construct(arg);
- if (frame->argc() > i)
- QMetaType::convert(frame->argTypes()[i], frame->argv()[i], argumentType, arg);
+ if (isValid)
+ QMetaType::convert(frameType, frameVal, argumentType, arg);
}
transformedArguments[i] = arg;
@@ -453,12 +475,19 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
const QMetaType returnType = function->typedFunction->returnType;
const QMetaType frameReturn = frame->returnType();
+ bool returnsQVariantWrapper = false;
Q_ALLOCA_DECLARE(void, transformedResult);
if (frame->returnValue() && returnType != frameReturn) {
- if (returnType.sizeOf() > 0)
+ if (frameReturn == QMetaType::fromType<QVariant>()) {
+ void *returnValue = frame->returnValue();
+ new (returnValue) QVariant(returnType);
+ transformedResult = static_cast<QVariant *>(returnValue)->data();
+ returnsQVariantWrapper = true;
+ } else if (returnType.sizeOf() > 0) {
Q_ALLOCA_ASSIGN(void, transformedResult, returnType.sizeOf());
- else
+ } else {
transformedResult = frame; // Some non-null marker value
+ }
}
QQmlPrivate::AOTCompiledContext aotContext;
@@ -475,7 +504,7 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
&aotContext, transformedResult ? transformedResult : frame->returnValue(),
transformedArguments ? transformedArguments : frame->argv());
- if (transformedResult) {
+ if (transformedResult && !returnsQVariantWrapper) {
// Shortcut the common case of the AOT function returning a more generic QObject pointer
// that we need to QObject-cast. No need to construct or destruct anything in that case.
if ((frameReturn.flags() & QMetaType::PointerToQObject)
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index bdebba53d0..4304934019 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -880,7 +880,8 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
-static ObjectPropertyResult loadObjectProperty(
+template<bool StrictType = false>
+ObjectPropertyResult loadObjectProperty(
QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
{
QQmlData *qmlData = QQmlData::get(object);
@@ -890,8 +891,12 @@ static ObjectPropertyResult loadObjectProperty(
return ObjectPropertyResult::Deleted;
Q_ASSERT(!QQmlData::wasDeleted(object));
const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
- if (!inherits(qmlData->propertyCache.data(), propertyCache))
+ if (StrictType) {
+ if (qmlData->propertyCache.data() != propertyCache)
+ return ObjectPropertyResult::NeedsInit;
+ } else if (!inherits(qmlData->propertyCache.data(), propertyCache)) {
return ObjectPropertyResult::NeedsInit;
+ }
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
const int coreIndex = property->coreIndex();
@@ -930,7 +935,35 @@ static ObjectPropertyResult loadFallbackProperty(
return ObjectPropertyResult::OK;
}
-template<typename Op>
+ObjectPropertyResult loadObjectAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+{
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadObjectProperty<true>(l, object, variant, qmlContext);
+
+ *variant = QVariant(propType);
+ return loadObjectProperty<true>(l, object, variant->data(), qmlContext);
+}
+
+ObjectPropertyResult loadFallbackAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadFallbackProperty(l, object, variant, qmlContext);
+
+ *variant = QVariant(propType);
+ return loadFallbackProperty(l, object, variant->data(), qmlContext);
+}
+
+template<bool StrictType, typename Op>
static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
{
const QQmlData *qmlData = QQmlData::get(object);
@@ -939,24 +972,30 @@ static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object
if (qmlData->isQueuedForDeletion)
return ObjectPropertyResult::Deleted;
Q_ASSERT(!QQmlData::wasDeleted(object));
- if (!inherits(qmlData->propertyCache.data(), l->qobjectLookup.propertyCache))
+ if (StrictType) {
+ if (qmlData->propertyCache.data() != l->qobjectLookup.propertyCache)
+ return ObjectPropertyResult::NeedsInit;
+ } else if (!inherits(qmlData->propertyCache.data(), l->qobjectLookup.propertyCache)) {
return ObjectPropertyResult::NeedsInit;
+ }
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
op(property);
return ObjectPropertyResult::OK;
}
+template<bool StrictType = false>
static ObjectPropertyResult resetObjectProperty(QV4::Lookup *l, QObject *object)
{
- return changeObjectProperty(l, object, [&](const QQmlPropertyData *property) {
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
property->resetProperty(object, {});
});
}
+template<bool StrictType = false>
static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
{
- return changeObjectProperty(l, object, [&](const QQmlPropertyData *property) {
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
property->writeProperty(object, value, {});
});
}
@@ -1061,10 +1100,55 @@ static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
return true;
}
+static ObjectPropertyResult storeObjectAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeObjectProperty<true>(l, object, variant);
+
+ if (!variant->isValid())
+ return resetObjectProperty<true>(l, object);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeObjectProperty<true>(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeObjectProperty<true>(l, object, converted.data());
+}
+
+static ObjectPropertyResult storeFallbackAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeFallbackProperty(l, object, variant);
+
+ if (!propType.isValid())
+ return resetFallbackProperty(l, object);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeFallbackProperty(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeFallbackProperty(l, object, converted.data());
+}
+
enum class ObjectLookupResult {
Failure,
Object,
- Fallback
+ Fallback,
+ ObjectAsVariant,
+ FallbackAsVariant,
};
static ObjectLookupResult initObjectLookup(
@@ -1094,6 +1178,7 @@ static ObjectLookupResult initObjectLookup(
name.getPointer(), object, aotContext->qmlContext);
}
+ const bool doVariantLookup = type == QMetaType::fromType<QVariant>();
if (!property) {
const QMetaObject *metaObject = object->metaObject();
if (!metaObject)
@@ -1105,7 +1190,7 @@ static ObjectLookupResult initObjectLookup(
return ObjectLookupResult::Failure;
const QMetaProperty property = metaObject->property(coreIndex);
- if (!isTypeCompatible(type, property.metaType()))
+ if (!doVariantLookup && !isTypeCompatible(type, property.metaType()))
return ObjectLookupResult::Failure;
l->releasePropertyCache();
@@ -1115,16 +1200,21 @@ static ObjectLookupResult initObjectLookup(
l->qobjectFallbackLookup.notifyIndex =
QMetaObjectPrivate::signalIndex(property.notifySignal());
l->qobjectFallbackLookup.isConstant = property.isConstant() ? 1 : 0;
- return ObjectLookupResult::Fallback;
+ return doVariantLookup
+ ? ObjectLookupResult::FallbackAsVariant
+ : ObjectLookupResult::Fallback;
}
- if (!isTypeCompatible(type, property->propType()))
+ if (!doVariantLookup && !isTypeCompatible(type, property->propType()))
return ObjectLookupResult::Failure;
Q_ASSERT(ddata->propertyCache);
QV4::setupQObjectLookup(l, ddata, property);
- return ObjectLookupResult::Object;
+
+ return doVariantLookup
+ ? ObjectLookupResult::ObjectAsVariant
+ : ObjectLookupResult::Object;
}
static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
@@ -1161,14 +1251,16 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
if (l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
- || l->getter == QV4::Lookup::getterQObject) {
+ || l->getter == QV4::Lookup::getterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant) {
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
QQmlData::flushPendingBinding(object, property->coreIndex());
captureObjectProperty(object, l->qobjectLookup.propertyCache, property, qmlContext);
return true;
}
- if (l->getter == QV4::Lookup::getterFallback) {
+ if (l->getter == QV4::Lookup::getterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant) {
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
QQmlData::flushPendingBinding(object, coreIndex);
captureFallbackProperty(
@@ -1224,7 +1316,9 @@ QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
|| l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty
|| l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
|| l->getter == QV4::Lookup::getterQObject
- || l->setter == QV4::Lookup::setterQObject) {
+ || l->setter == QV4::Lookup::setterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant
+ || l->setter == QV4::Lookup::setterQObjectAsVariant) {
return l->qobjectLookup.propertyData->propType();
} else if (l->getter == QV4::QQmlValueTypeWrapper::lookupGetter) {
return QMetaType(l->qgadgetLookup.metaType);
@@ -1237,6 +1331,8 @@ QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
return QMetaType::fromType<QObject *>();
} else if (l->getter == QV4::Lookup::getterFallback
|| l->setter == QV4::Lookup::setterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant
+ || l->setter == QV4::Lookup::setterFallbackAsVariant
|| l->qmlContextPropertyGetter
== QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
const QMetaObject *metaObject
@@ -1272,33 +1368,37 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
l.forCall = false;
ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit;
switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) {
+ case ObjectLookupResult::ObjectAsVariant:
case ObjectLookupResult::Object: {
const QMetaType propType = l.qobjectLookup.propertyData->propType();
- if (type == propType) {
+ if (isTypeCompatible(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());
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
}
l.qobjectLookup.propertyCache->release();
break;
}
+ case ObjectLookupResult::FallbackAsVariant:
case ObjectLookupResult::Fallback: {
const QMetaObject *metaObject
= reinterpret_cast<const QMetaObject *>(l.qobjectFallbackLookup.metaObject - 1);
const QMetaType propType
= metaObject->property(l.qobjectFallbackLookup.coreIndex).metaType();
- if (type == propType) {
+ if (isTypeCompatible(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());
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
}
break;
@@ -1574,9 +1674,11 @@ void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType
}
switch (initObjectLookup(this, l, qmlScopeObject, type)) {
+ case ObjectLookupResult::ObjectAsVariant:
case ObjectLookupResult::Object:
l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
break;
+ case ObjectLookupResult::FallbackAsVariant:
case ObjectLookupResult::Fallback:
l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeFallbackProperty;
break;
@@ -1742,6 +1844,10 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ
result = loadObjectProperty(l, object, target, qmlContext);
else if (l->getter == QV4::Lookup::getterFallback)
result = loadFallbackProperty(l, object, target, qmlContext);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = loadObjectAsVariant(l, object, target, qmlContext);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = loadFallbackAsVariant(l, object, target, qmlContext);
else
return false;
@@ -1768,9 +1874,15 @@ void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaT
case ObjectLookupResult::Object:
l->getter = QV4::Lookup::getterQObject;
break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->getter = QV4::Lookup::getterQObjectAsVariant;
+ break;
case ObjectLookupResult::Fallback:
l->getter = QV4::Lookup::getterFallback;
break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->getter = QV4::Lookup::getterFallbackAsVariant;
+ break;
case ObjectLookupResult::Failure:
engine->handle()->throwTypeError();
break;
@@ -1884,6 +1996,10 @@ bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *valu
result = storeObjectProperty(l, object, value);
else if (l->setter == QV4::Lookup::setterFallback)
result = storeFallbackProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterQObjectAsVariant)
+ result = storeObjectAsVariant(engine->handle(), l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallbackAsVariant)
+ result = storeFallbackAsVariant(engine->handle(), l, object, value);
else
return false;
@@ -1910,9 +2026,15 @@ void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaT
case ObjectLookupResult::Object:
l->setter = QV4::Lookup::setterQObject;
break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->setter = QV4::Lookup::setterQObjectAsVariant;
+ break;
case ObjectLookupResult::Fallback:
l->setter = QV4::Lookup::setterFallback;
break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->setter = QV4::Lookup::setterFallbackAsVariant;
+ break;
case ObjectLookupResult::Failure:
engine->handle()->throwTypeError();
break;