aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4function.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-21 14:11:41 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-26 20:42:49 +0200
commit9eb6240ebd0b7f52ec49aba757a8c355b25203e0 (patch)
treecff2b25ad5798206830bb1cb1ea1c036610634d6 /src/qml/jsruntime/qv4function.cpp
parenta3389d6bf238c46816fd1133c1258102e36c4b10 (diff)
QML: Improve the JS-to-JS type check when enforcing signatures
We do not have to coerce via the C++ type. Rather, we match the JavaScript representations of the types and coerce as needed. Task-number: QTBUG-113527 Change-Id: Id5c30cd46293f2d7aedd699f141a9fe19511b622 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r--src/qml/jsruntime/qv4function.cpp75
1 files changed, 32 insertions, 43 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 860309a4d2..c1725f8818 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -68,7 +68,7 @@ ReturnedValue Function::call(
});
case JsTyped:
return QV4::coerceAndCall(
- context->engine(), aotCompiledFunction, thisObject, argv, argc,
+ context->engine(), jsTypedFunction, compiledFunction, thisObject, argv, argc,
[this, context](const Value *thisObject, const Value *argv, int argc) {
return doCall(this, thisObject, argv, argc, context);
});
@@ -91,6 +91,12 @@ void Function::destroy()
delete this;
}
+static bool isSpecificType(const CompiledData::ParameterType &type)
+{
+ return type.typeNameIndexOrCommonType()
+ != (type.indexIsCommonType() ? quint32(CompiledData::CommonType::Invalid) : 0);
+}
+
Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
const CompiledData::Function *function,
const QQmlPrivate::AOTCompiledFunction *aotFunction)
@@ -111,72 +117,55 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
- const bool enforcesSignature = !aotFunction && unit->enforcesFunctionSignature();
- bool hasTypes = false;
+ bool enforceJsTypes = !aotFunction && unit->enforcesFunctionSignature();
+
for (quint32 i = 0; i < compiledFunction->nFormals; ++i) {
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable);
- if (enforcesSignature
- && !hasTypes
- && formalsIndices[i].type.typeNameIndexOrCommonType()
- != quint32(QV4::CompiledData::CommonType::Invalid)) {
- hasTypes = true;
- }
+ if (enforceJsTypes && !isSpecificType(formalsIndices[i].type))
+ enforceJsTypes = false;
}
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
- if (!enforcesSignature)
+ // If a function has any typed arguments, but an untyped return value, the return value is void.
+ // If it doesn't have any arguments at all and the return value is untyped, the function is
+ // untyped. Users can specifically set the return type to "void" to have it enforced.
+ if (!enforceJsTypes || (nFormals == 0 && !isSpecificType(compiledFunction->returnType)))
return;
- if (!hasTypes
- && compiledFunction->returnType.typeNameIndexOrCommonType()
- == quint32(QV4::CompiledData::CommonType::Invalid)) {
- return;
- }
+ JSTypedFunction *synthesized = new JSTypedFunction;
- QQmlPrivate::AOTCompiledFunction *synthesized = new QQmlPrivate::AOTCompiledFunction;
QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine->qmlEngine());
-
- auto findMetaType = [&](const CompiledData::ParameterType &param) {
+ auto findQmlType = [&](const CompiledData::ParameterType &param) {
const quint32 type = param.typeNameIndexOrCommonType();
if (param.indexIsCommonType()) {
- if (param.isList()) {
- return QQmlPropertyCacheCreatorBase::listTypeForPropertyType(
- QV4::CompiledData::CommonType(type));
- }
- return QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(
- QV4::CompiledData::CommonType(type));
+ return QQmlMetaType::qmlType(QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(
+ QV4::CompiledData::CommonType(type)));
}
if (type == 0)
- return QMetaType();
-
- const QQmlType qmltype = unit->typeNameCache->query(unit->stringAt(type)).type;
- if (!qmltype.isValid())
- return QMetaType();
+ return QQmlType();
- const QMetaType metaType = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
- if (metaType.isValid())
- return metaType;
+ const QQmlType qmltype = unit->typeNameCache->query<QQmlImport::AllowRecursion>(
+ unit->stringAt(type)).type;
+ if (!qmltype.isValid() || qmltype.typeId().isValid())
+ return qmltype;
if (!qmltype.isComposite()) {
- if (!qmltype.isInlineComponentType())
- return QMetaType();
- const QQmlType qmlType = unit->qmlTypeForComponent(qmltype.elementName());
- return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ return qmltype.isInlineComponentType()
+ ? unit->qmlTypeForComponent(qmltype.elementName())
+ : QQmlType();
}
- const QQmlType qmlType = enginePrivate->typeLoader.getType(
- qmltype.sourceUrl())->compilationUnit()->qmlType;
- return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ return enginePrivate->typeLoader.getType(qmltype.sourceUrl())->compilationUnit()->qmlType;
};
for (quint16 i = 0; i < nFormals; ++i)
- synthesized->argumentTypes.append(findMetaType(formalsIndices[i].type));
+ synthesized->argumentTypes.append(findQmlType(formalsIndices[i].type));
- synthesized->returnType = findMetaType(compiledFunction->returnType);
- aotCompiledFunction = synthesized;
+ synthesized->returnType = findQmlType(compiledFunction->returnType);
+ jsTypedFunction = synthesized;
kind = JsTyped;
}
@@ -187,7 +176,7 @@ Function::~Function()
delete codeRef;
}
if (kind == JsTyped)
- delete aotCompiledFunction;
+ delete jsTypedFunction;
}
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)