diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 529affcb2a..0e968fdc95 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -120,12 +120,11 @@ static bool fromMatchingType( return true; } - QVariant converted = QQmlValueTypeProvider::createValueType(s, parameterType); - if (converted.isValid()) { - callConstructor(mo, i, converted.data(), allocate()); - return true; - } + // Do not recursively try to create parameters here. This may end up in infinite recursion. + // At this point, s should be a builtin type. For builtin types + // the QMetaType converters are good enough. + QVariant converted(parameterType); if (QMetaType::convert(parameter.metaType(), parameter.constData(), parameterType, converted.data())) { callConstructor(mo, i, converted.data(), allocate()); @@ -157,14 +156,11 @@ static bool fromMatchingType(const QMetaObject *mo, QVariant s, Allocate &&alloc return true; } - QVariant parameter = QQmlValueTypeProvider::createValueType(s, parameterType); - if (parameter.isValid()) { - callConstructor(mo, i, parameter.data(), allocate()); - return true; - } + // Do not recursively try to create parameters here. This may end up in infinite recursion. // At this point, s should be a builtin type. For builtin types // the QMetaType converters are good enough. + QVariant parameter(parameterType); if (QMetaType::convert(sourceMetaType, s.constData(), parameterType, parameter.data())) { callConstructor(mo, i, parameter.data(), allocate()); return true; diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index e17dc5aebe..1d0cb36b6b 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -485,8 +485,10 @@ bool QQmlJSTypeResolver::adjustTrackedType( // If we cannot convert to the new type without the help of e.g. lookupResultMetaType(), // we better not change the type. - if (!canPrimitivelyConvertFromTo(tracked, conversion)) + if (!canPrimitivelyConvertFromTo(tracked, conversion) + && !selectConstructor(conversion, tracked, nullptr).isValid()) { return false; + } it->replacement = comparableType(conversion); *it->clone = std::move(*QQmlJSScope::clone(conversion)); @@ -508,8 +510,10 @@ bool QQmlJSTypeResolver::adjustTrackedType( // If we cannot convert to the new type without the help of e.g. lookupResultMetaType(), // we better not change the type. - if (!canPrimitivelyConvertFromTo(tracked, result)) + if (!canPrimitivelyConvertFromTo(tracked, result) + && !selectConstructor(result, tracked, nullptr).isValid()) { return false; + } it->replacement = comparableType(result); *mutableTracked = std::move(*QQmlJSScope::clone(result)); @@ -569,7 +573,7 @@ QString QQmlJSTypeResolver::containedTypeName(const QQmlJSRegisterContent &conta bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSScope::ConstPtr &from, const QQmlJSScope::ConstPtr &to) const { - if (canPrimitivelyConvertFromTo(from, to)) + if (canPrimitivelyConvertFromTo(from, to) || selectConstructor(to, from, nullptr).isValid()) return true; // ### need a generic solution for custom cpp types: @@ -1005,7 +1009,7 @@ QQmlJSMetaMethod QQmlJSTypeResolver::selectConstructor( { // If the "from" type can hold the target type, we should not try to coerce // it to any constructor argument. - if (canHold(passedArgumentType, type)) + if (type.isNull() || canHold(passedArgumentType, type)) return QQmlJSMetaMethod(); if (QQmlJSScope::ConstPtr extension = type->extensionType().scope) { @@ -1041,6 +1045,8 @@ QQmlJSMetaMethod QQmlJSTypeResolver::selectConstructor( if (equals(passedArgumentType, methodArgumentType)) return method; + // Do not select further ctors here. We don't want to do multi-step construction as that + // is confusing and easily leads to infinite recursion. if (!candidate.isValid() && canPrimitivelyConvertFromTo(passedArgumentType, methodArgumentType)) { candidate = method; @@ -1165,7 +1171,7 @@ bool QQmlJSTypeResolver::canPrimitivelyConvertFromTo( return true; } - return selectConstructor(to, from, nullptr).isValid(); + return false; } QQmlJSRegisterContent QQmlJSTypeResolver::lengthProperty(