QV4::Engine::toVariant: Use metatype instead of metatype id

This way, we can avoid the costly id to metatype lookup in case where we
actually need the full metatype.

Task-number: QTBUG-88766
Change-Id: Ibe29b323007f00d2f8d1807fb9b64f9a8f87e807
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
Fabian Kosmale 2021-03-24 15:36:37 +01:00
parent 3ce1ee554b
commit d009c0088b
20 changed files with 56 additions and 56 deletions

View File

@ -666,7 +666,7 @@ QVariant QJSManagedValue::toVariant() const
if (d->isString())
return QVariant(d->toQString());
if (QV4::Managed *m = d->as<QV4::Managed>())
return m->engine()->toVariant(*d, -1, true);
return m->engine()->toVariant(*d, QMetaType{}, true);
Q_UNREACHABLE();
return QVariant();

View File

@ -626,7 +626,7 @@ QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const
if (val.isString())
return QVariant(val.toQString());
if (QV4::Managed *m = val.as<QV4::Managed>())
return m->engine()->toVariant(val, /*typeHint*/ -1, behavior == RetainJSObjects);
return m->engine()->toVariant(val, /*typeHint*/ QMetaType{}, behavior == RetainJSObjects);
Q_ASSERT(false);
return QVariant();

View File

@ -1484,7 +1484,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
// Variant conversion code
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
static QObject *qtObjectFromJS(const QV4::Value &value);
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
@ -1496,17 +1496,11 @@ static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &
return v4->metaTypeToJS(value.metaType(), value.constData());
}
QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects)
{
return ::toVariant(this, value, typeHint, createJSValueForObjects, nullptr);
}
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMetaType metaType, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
{
Q_ASSERT (!value.isEmpty());
QV4::Scope scope(e);
int typeHint = metaType.id();
if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
return v->d()->data();
@ -1517,7 +1511,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (typeHint == QMetaType::QJsonValue)
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
if (typeHint == qMetaTypeId<QJSValue>())
if (metaType == QMetaType::fromType<QJSValue>())
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
if (value.as<QV4::Object>()) {
@ -1569,8 +1563,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (succeeded)
return retn;
#endif
if (typeHint != -1) {
auto metaType = QMetaType(typeHint);
if (metaType.isValid()) {
retn = QVariant(metaType, nullptr);
auto retnAsIterable = retn.value<QSequentialIterable>();
if (retnAsIterable.metaContainer().canAddValue()) {
@ -1591,7 +1584,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
continue;
}
}
asVariant = toVariant(e, arrayValue, valueMetaType.id(), false,
asVariant = toVariant(e, arrayValue, valueMetaType, false,
visitedObjects);
if (valueMetaType.id() != QMetaType::QVariant) {
auto originalType = asVariant.metaType();
@ -1653,6 +1646,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return objectToVariant(e, o, visitedObjects);
}
QVariant ExecutionEngine::toVariant(const Value &value, QMetaType typeHint, bool createJSValueForObjects)
{
return ::toVariant(this, value, typeHint, createJSValueForObjects, nullptr);
}
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects)
{
Q_ASSERT(o);
@ -1681,7 +1680,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
int length = a->getLength();
for (int ii = 0; ii < length; ++ii) {
v = a->get(ii);
list << ::toVariant(e, v, -1, /*createJSValueForObjects*/false, visitedObjects);
list << ::toVariant(e, v, QMetaType {}, /*createJSValueForObjects*/false, visitedObjects);
}
result = list;
@ -1697,7 +1696,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
break;
QString key = name->toQStringNoThrow();
map.insert(key, ::toVariant(e, val, /*type hint*/-1, /*createJSValueForObjects*/false, visitedObjects));
map.insert(key, ::toVariant(e, val, /*type hint*/ QMetaType {}, /*createJSValueForObjects*/false, visitedObjects));
}
result = map;
@ -2328,7 +2327,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
if (a) {
*reinterpret_cast<QVariantList *>(data) = a->engine()->toVariant(
*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
*a, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false).toList();
return true;
}
break;
@ -2343,7 +2342,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
}
case QMetaType::QVariant:
if (const QV4::Managed *m = value.as<QV4::Managed>())
*reinterpret_cast<QVariant*>(data) = m->engine()->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false);
*reinterpret_cast<QVariant*>(data) = m->engine()->toVariant(value, /*typeHint*/QMetaType{}, /*createJSValueForObjects*/false);
else if (value.isNull())
*reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
else if (value.isUndefined())

View File

@ -681,7 +681,7 @@ public:
QQmlError catchExceptionAsQmlError();
// variant conversions
QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true);
QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjects = true);
QV4::ReturnedValue fromVariant(const QVariant &);
QVariantMap variantMapFromJS(const QV4::Object *o);

View File

@ -233,7 +233,7 @@ void convertAndCall(ExecutionEngine *engine, const Value *thisObject,
// When the return type is QVariant, JS objects are to be returned as
// QJSValue wrapped in QVariant. metaTypeFromJS unwraps them, unfortunately.
if (resultType == QMetaType::fromType<QVariant>())
*static_cast<QVariant *>(result) = scope.engine->toVariant(jsResult, 0);
*static_cast<QVariant *>(result) = scope.engine->toVariant(jsResult, QMetaType {});
else
scope.engine->metaTypeFromJS(jsResult, resultType, result);
}

View File

@ -617,9 +617,9 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
} else {
QVariant v;
if (property->isQList())
v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
v = scope.engine->toVariant(value, QMetaType::fromType<QList<QObject *> >());
else
v = scope.engine->toVariant(value, propType);
v = scope.engine->toVariant(value, property->propType());
QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
@ -1524,7 +1524,7 @@ static int MatchScore(const QV4::Value &actual, QMetaType conversionMetaType)
if (obj->as<QV4::VariantObject>()) {
if (conversionType == qMetaTypeId<QVariant>())
return 0;
if (obj->engine()->toVariant(actual, -1).metaType() == conversionMetaType)
if (obj->engine()->toVariant(actual, QMetaType {}).metaType() == conversionMetaType)
return 0;
else
return 10;
@ -1547,7 +1547,7 @@ static int MatchScore(const QV4::Value &actual, QMetaType conversionMetaType)
}
if (obj->as<QV4::QQmlValueTypeWrapper>()) {
const QVariant v = obj->engine()->toVariant(actual, -1);
const QVariant v = obj->engine()->toVariant(actual, QMetaType {});
if (v.userType() == conversionType)
return 0;
else if (v.canConvert(conversionMetaType))
@ -1895,7 +1895,7 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
else if (!value.isNull() && !value.isUndefined()) // null and undefined are nullptr
return false;
} else if (callType == qMetaTypeId<QVariant>()) {
qvariantPtr = new (&allocData) QVariant(scope.engine->toVariant(value, -1));
qvariantPtr = new (&allocData) QVariant(scope.engine->toVariant(value, QMetaType {}));
type = callType;
} else if (callType == qMetaTypeId<QList<QObject*> >()) {
qlistPtr = new (&allocData) QList<QObject *>();
@ -1986,7 +1986,7 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
type = -1;
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
QVariant v = scope.engine->toVariant(value, callType);
QVariant v = scope.engine->toVariant(value, metaType);
const QMetaType callMetaType(callType);
if (v.metaType() == callMetaType) {

View File

@ -253,7 +253,7 @@ public:
qsizetype count = size();
const QMetaType valueMetaType = meta(d())->valueMetaType();
const QVariant element = engine()->toVariant(value, valueMetaType.id(), false);
const QVariant element = engine()->toVariant(value, valueMetaType, false);
if (index == count) {
append(element);
@ -680,7 +680,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i) {
const QMetaType valueMetaType = meta->valueMetaType();
QVariant variant = scope.engine->toVariant(a->get(i), valueMetaType.id(), false);
QVariant variant = scope.engine->toVariant(a->get(i), valueMetaType, false);
if (variant.metaType() != valueMetaType && !variant.convert(valueMetaType))
variant = QVariant(valueMetaType);
meta->addValueAtEnd(result.data(), variant.constData());

View File

@ -413,7 +413,8 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
QQmlEngine *qmlEngine = engine();
QV4::ExecutionEngine *v4engine = qmlEngine->handle();
const int type = valueTypeData.isValid() ? valueTypeData.propType().id() : core.propType().id();
const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
const int type = metaType.id();
QQmlJavaScriptExpression::DeleteWatcher watcher(this);
@ -422,13 +423,13 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
if (isUndefined) {
} else if (core.isQList()) {
value = v4engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
value = v4engine->toVariant(result, QMetaType::fromType<QList<QObject *> >());
} else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)nullptr);
} else if (core.propType().id() == qMetaTypeId<QList<QUrl> >()) {
value = QQmlPropertyPrivate::urlSequence(v4engine->toVariant(result, qMetaTypeId<QList<QUrl>>()));
} else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
value = v4engine->toVariant(result, type);
value = QQmlPropertyPrivate::urlSequence(v4engine->toVariant(result, QMetaType::fromType<QList<QUrl>>()));
} else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
value = v4engine->toVariant(result, metaType);
}
if (hasError()) {
@ -448,9 +449,9 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
} else if (isUndefined && core.isResettable()) {
void *args[] = { nullptr };
QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
} else if (isUndefined && type == qMetaTypeId<QVariant>()) {
} else if (isUndefined && type == QMetaType::QVariant) {
QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
} else if (type == qMetaTypeId<QJSValue>()) {
} else if (metaType == QMetaType::fromType<QJSValue>()) {
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
if (f && f->isBinding()) {
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
@ -526,7 +527,7 @@ QVariant QQmlBinding::evaluate()
ep->dereferenceScarceResources();
return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
return scope.engine->toVariant(result, QMetaType::fromType<QList<QObject*> >());
}
void QQmlBinding::expressionChanged()

View File

@ -281,7 +281,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
QV4::Scope scope(engine->handle());
QV4::ScopedValue result(scope, v4value(isUndefined));
if (!hasError())
rv = scope.engine->toVariant(result, -1);
rv = scope.engine->toVariant(result, QMetaType {});
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.

View File

@ -284,7 +284,7 @@ bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
break;
}
QVariant resultVariant(scope.engine->toVariant(result, metaType.id()));
QVariant resultVariant(scope.engine->toVariant(result, metaType));
resultVariant.convert(metaType);
const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
metaType.destruct(dataPtr);

View File

@ -679,7 +679,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QMetaProperty property = metaObject->property(pd.coreIndex());
Q_ASSERT(property.isValid());
QVariant v = v4->toVariant(value, property.userType());
QVariant v = v4->toVariant(value, property.metaType());
if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
v = v.toInt();

View File

@ -1062,7 +1062,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const
const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (v)
return v->d()->data();
return engine->toVariant(*(md->data() + id), -1);
return engine->toVariant(*(md->data() + id), QMetaType {});
}
return QVariant();
}

View File

@ -265,7 +265,7 @@ static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValu
// expects a null variant. (this is because of QTBUG-40880)
if (value->isNull())
return QVariant();
return engine->toVariant(value, /*typehint*/-1);
return engine->toVariant(value, /*typehint*/ QMetaType {});
}
static ReturnedValue qmlsqldatabase_executeSql(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)

View File

@ -369,10 +369,10 @@ QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject
QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
if (!modelData->cachedData.isEmpty()) {
if (modelData->cachedData.count() > 1) {
modelData->cachedData[propertyId] = scope.engine->toVariant(argv[0], QMetaType::UnknownType);
modelData->cachedData[propertyId] = scope.engine->toVariant(argv[0], QMetaType {});
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
} else if (modelData->cachedData.count() == 1) {
modelData->cachedData[0] = scope.engine->toVariant(argv[0], QMetaType::UnknownType);
modelData->cachedData[0] = scope.engine->toVariant(argv[0], QMetaType {});
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
}
@ -603,7 +603,7 @@ public:
if (!argc)
return v4->throwTypeError();
static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QMetaType::UnknownType));
static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QMetaType {}));
return QV4::Encode::undefined();
}

View File

@ -2033,7 +2033,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
propertyName = it.nextPropertyNameAsString(v);
if (propertyName->isNull())
break;
cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QMetaType::UnknownType));
cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QMetaType {}));
}
cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;

View File

@ -627,7 +627,7 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (role.type == ListLayout::Role::QObject)
roleIndex = e->setQObjectProperty(role, o);
} else if (QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::QUrl, true);
} else if (QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
QUrl qurl = maybeUrl.toUrl();
@ -719,7 +719,7 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
if (r.type == ListLayout::Role::QObject)
e->setQObjectPropertyFast(r, o);
} else {
QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::QUrl, true);
QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
const QUrl qurl = maybeUrl.toUrl();
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
@ -1554,7 +1554,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d
} else if (role.type == ListLayout::Role::VariantMap) {
roleIndex = setVariantMapProperty(role, o);
} else if (role.type == ListLayout::Role::Url) {
QVariant maybeUrl = o->engine()->toVariant(o.asReturnedValue(), QMetaType::QUrl, true);
QVariant maybeUrl = o->engine()->toVariant(o.asReturnedValue(), QMetaType::fromType<QUrl>(), true);
if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
roleIndex = setUrlProperty(role, maybeUrl.toUrl());
}

View File

@ -556,7 +556,7 @@ void QuickTestResult::stringify(QQmlV4Function *args)
if (value->isObject()
&& !value->as<QV4::FunctionObject>()
&& !value->as<QV4::ArrayObject>()) {
QVariant v = scope.engine->toVariant(value, QMetaType::UnknownType);
QVariant v = scope.engine->toVariant(value, QMetaType {});
if (v.isValid()) {
switch (v.userType()) {
case QMetaType::QVector3D:

View File

@ -264,7 +264,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
return;
}
#endif
const QVariant variant = engine->toVariant(v, QMetaType::QUrl, false);
const QVariant variant = engine->toVariant(v, QMetaType::fromType<QUrl>(), false);
if (variant.userType() == QMetaType::QUrl) {
serializeString(data, variant.value<QUrl>().toString(), WorkerUrl);
return;

View File

@ -1433,7 +1433,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(const QV4::FunctionOb
QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
QColor color = scope.engine->toVariant(value, QMetaType::fromType<QColor>()).value<QColor>();
if (color.isValid()) {
r->d()->context()->state.fillStyle = color;
r->d()->context()->buffer()->setFillStyle(color);
@ -1542,7 +1542,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(const QV4::Function
QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue());
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
QColor color = scope.engine->toVariant(value, QMetaType::fromType<QColor>()).value<QColor>();
if (color.isValid()) {
r->d()->context()->state.strokeStyle = color;
r->d()->context()->buffer()->setStrokeStyle(color);
@ -1774,7 +1774,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(const QV4::F
if (argc >= 2) {
QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QColor color = scope.engine->toVariant(argv[0], qMetaTypeId<QColor>()).value<QColor>();
QColor color = scope.engine->toVariant(argv[0], QMetaType::fromType<QColor>()).value<QColor>();
if (color.isValid()) {
int patternMode = argv[1].toInt32();
Qt::BrushStyle style = Qt::SolidPattern;
@ -3588,7 +3588,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(const QV4::
QColor color;
if (argv[1].as<Object>()) {
color = scope.engine->toVariant(argv[1], qMetaTypeId<QColor>()).value<QColor>();
color = scope.engine->toVariant(argv[1], QMetaType::fromType<QColor>()).value<QColor>();
} else {
color = qt_color_from_string(argv[1]);
}

View File

@ -2831,7 +2831,7 @@ void tst_qqmlecmascript::callQtInvokables()
{
QV4::ScopedValue ret(scope, EVALUATE("object.method_NoArgs_QPointF()"));
QVERIFY(!ret->isUndefined());
QCOMPARE(scope.engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
QCOMPARE(scope.engine->toVariant(ret, QMetaType {}), QVariant(QPointF(123, 4.5)));
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 3);
QCOMPARE(o->actuals().count(), 0);