[new compiler] Fix timing of property assignment error handling
authorSimon Hausmann <simon.hausmann@digia.com>
Mon, 27 Jan 2014 15:00:54 +0000 (16:00 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 29 Jan 2014 09:08:46 +0000 (10:08 +0100)
Most property assignment errors are now handled at type compile time, just
like in the old compiler. This speeds up the object creation code and
restores behavior expected in the qqmllanguage tests.

Change-Id: If213cd0bfa4dd51d9065c27809a79a6495c9f3ce
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qqmltypecompiler.cpp
src/qml/compiler/qqmltypecompiler_p.h
src/qml/qml/qqmlobjectcreator.cpp
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp

index c090f0ab4130c0d3ab0e53d66da1ec4954d036ca..6fe3567031dd329643bc5a326dad66810d17b58b 100644 (file)
@@ -46,6 +46,7 @@
 #include <private/qqmlcustomparser_p.h>
 #include <private/qqmlvmemetaobject_p.h>
 #include <private/qqmlcomponent_p.h>
+#include <private/qqmlstringconverters_p.h>
 
 #define COMPILE_EXCEPTION(token, desc) \
     { \
@@ -389,9 +390,14 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
 
         bool notInRevision = false;
         instantiatingProperty = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), &notInRevision);
-        if (instantiatingProperty && instantiatingProperty->isQObject()) {
-            baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
-            Q_ASSERT(baseTypeCache);
+        if (instantiatingProperty) {
+            if (instantiatingProperty->isQObject()) {
+                baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType);
+                Q_ASSERT(baseTypeCache);
+            } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) {
+                baseTypeCache = enginePrivate->cache(vt->metaObject());
+                Q_ASSERT(baseTypeCache);
+            }
         }
     }
 
@@ -1145,6 +1151,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
 
 QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, const QVector<int> &runtimeFunctionIndices)
     : QQmlCompilePass(typeCompiler)
+    , enginePrivate(typeCompiler->enginePrivate())
     , qmlUnit(typeCompiler->qmlUnit())
     , resolvedTypes(*typeCompiler->resolvedTypes())
     , propertyCaches(typeCompiler->propertyCaches())
@@ -1201,7 +1208,16 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
 
     PropertyResolver propertyResolver(propertyCache);
 
-    QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+    QString defaultPropertyName;
+    QQmlPropertyData *defaultProperty = 0;
+    if (obj->indexOfDefaultProperty != -1) {
+        QQmlPropertyCache *cache = propertyCache->parent();
+        defaultPropertyName = cache->defaultPropertyName();
+        defaultProperty = cache->defaultProperty();
+    } else {
+        defaultPropertyName = propertyCache->defaultPropertyName();
+        defaultProperty = propertyCache->defaultProperty();
+    }
 
     const QV4::CompiledData::Binding *binding = obj->bindingTable();
     for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
@@ -1231,7 +1247,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
                 continue;
         }
 
-        const QString name = stringAt(binding->propertyNameIndex);
+        QString name = stringAt(binding->propertyNameIndex);
 
         bool bindingToDefaultProperty = false;
 
@@ -1256,10 +1272,29 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
                COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property"));
 
            pd = defaultProperty;
+           name = defaultPropertyName;
            bindingToDefaultProperty = true;
         }
 
-        if (!pd) {
+        if (pd) {
+            if (!pd->isWritable()
+                && !pd->isQList()
+                && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
+                && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+                && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+                ) {
+                recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
+                return false;
+            }
+
+            if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+                if (!validateLiteralBinding(propertyCache, pd, binding))
+                    return false;
+            } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+                if (!validateObjectBinding(pd, binding))
+                    return false;
+            }
+        } else {
             if (customParser) {
                 customBindings << binding;
                 continue;
@@ -1289,4 +1324,313 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
     return true;
 }
 
+bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+{
+    if (property->isEnum()) {
+        QString value = binding->valueAsString(&qmlUnit->header);
+        QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex);
+        bool ok;
+        if (p.isFlagType()) {
+            p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
+        } else
+            p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
+
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+            return false;
+        }
+        return true;
+    }
+
+    switch (property->propType) {
+    case QMetaType::QVariant:
+    break;
+    case QVariant::String: {
+        if (binding->type != QV4::CompiledData::Binding::Type_String) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: string expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::StringList: {
+        if (binding->type != QV4::CompiledData::Binding::Type_String) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::ByteArray: {
+        if (binding->type != QV4::CompiledData::Binding::Type_String) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Url: {
+        if (binding->type != QV4::CompiledData::Binding::Type_String) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: url expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::UInt: {
+        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+            double d = binding->valueAsNumber();
+            if (double(uint(d)) == d)
+                return true;
+        }
+        recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+        return false;
+    }
+    break;
+    case QVariant::Int: {
+        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+            double d = binding->valueAsNumber();
+            if (double(int(d)) == d)
+                return true;
+        }
+        recordError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+        return false;
+    }
+    break;
+    case QMetaType::Float: {
+        if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Double: {
+        if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Color: {
+        bool ok = false;
+        QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+            return false;
+        }
+    }
+    break;
+#ifndef QT_NO_DATESTRING
+    case QVariant::Date: {
+        bool ok = false;
+        QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: date expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Time: {
+        bool ok = false;
+        QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: time expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::DateTime: {
+        bool ok = false;
+        QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
+            return false;
+        }
+    }
+    break;
+#endif // QT_NO_DATESTRING
+    case QVariant::Point: {
+        bool ok = false;
+        QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::PointF: {
+        bool ok = false;
+        QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Size: {
+        bool ok = false;
+        QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::SizeF: {
+        bool ok = false;
+        QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Rect: {
+        bool ok = false;
+        QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::RectF: {
+        bool ok = false;
+        QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
+        if (!ok) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Bool: {
+        if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Vector3D: {
+        struct {
+            float xp;
+            float yp;
+            float zy;
+        } vec;
+        if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::Vector4D: {
+        struct {
+            float xp;
+            float yp;
+            float zy;
+            float wp;
+        } vec;
+        if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
+            recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
+            return false;
+        }
+    }
+    break;
+    case QVariant::RegExp:
+        recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+        break;
+    default: {
+        // generate single literal value assignment to a list property if required
+        if (property->propType == qMetaTypeId<QList<qreal> >()) {
+            if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+                recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected"));
+                return false;
+            }
+            break;
+        } else if (property->propType == qMetaTypeId<QList<int> >()) {
+            bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+            if (ok) {
+                double n = binding->valueAsNumber();
+                if (double(int(n)) != n)
+                    ok = false;
+            }
+            if (!ok)
+                recordError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected"));
+            break;
+        } else if (property->propType == qMetaTypeId<QList<bool> >()) {
+            if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+                recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
+                return false;
+            }
+            break;
+        } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
+            if (binding->type != QV4::CompiledData::Binding::Type_String) {
+                recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
+                return false;
+            }
+            break;
+        } else if (property->propType == qMetaTypeId<QList<QString> >()) {
+            if (binding->type != QV4::CompiledData::Binding::Type_String) {
+                recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
+                return false;
+            }
+            break;
+        } else if (property->propType == qMetaTypeId<QJSValue>()) {
+            break;
+        } else if (property->propType == qMetaTypeId<QQmlScriptString>()) {
+            break;
+        }
+
+        // otherwise, try a custom type assignment
+        QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
+        if (!converter) {
+            recordError(binding->location, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+            return false;
+        }
+    }
+    break;
+    }
+    return true;
+}
+
+bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+{
+    if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+        return true;
+    if (isComponent(binding->value.objectIndex))
+        return true;
+
+    if (QQmlMetaType::isInterface(property->propType)) {
+        // Can only check at instantiation time if the created sub-object successfully casts to the
+        // target interface.
+        return true;
+    } else if (property->propType == QMetaType::QVariant) {
+        // We can convert everything to QVariant :)
+        return true;
+    } else if (property->isQList()) {
+        // ### TODO: list error handling
+        return true;
+    } else if (QQmlValueTypeFactory::isValueType(property->propType)) {
+        recordError(binding->location, tr("Unexpected object assignment"));
+        return false;
+    } else {
+        // We want to raw metaObject here as the raw metaobject is the
+        // actual property type before we applied any extensions that might
+        // effect the properties on the type, but don't effect assignability
+        QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
+
+        // Will be true if the assgned type inherits propertyMetaObject
+        bool isAssignable = false;
+        // Determine isAssignable value
+        if (propertyMetaObject) {
+            QQmlPropertyCache *c = propertyCaches.value(binding->value.objectIndex);
+            while (c && !isAssignable) {
+                isAssignable |= c == propertyMetaObject;
+                c = c->parent();
+            }
+        }
+
+        if (!isAssignable) {
+            recordError(binding->valueLocation, tr("Cannot assign object to property"));
+            return false;
+        }
+    }
+    return true;
+}
+
 QT_END_NAMESPACE
index 29c045816dc64072ca84d3d374dd7aac7f753673..b698d98f4e41e34b3e152dc9ad9b81972342f0db 100644 (file)
@@ -191,9 +191,12 @@ public:
 
 private:
     bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding);
+    bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
+    bool validateObjectBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
 
     bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
 
+    QQmlEnginePrivate *enginePrivate;
     const QV4::CompiledData::QmlUnit *qmlUnit;
     const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
     const QVector<QQmlPropertyCache *> &propertyCaches;
index bd5a2124087d24807efd1c3eabf9f21a17b992f2..b7dc1f4b9470a1f876622c561c9b865c5b1074f5 100644 (file)
@@ -187,8 +187,9 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
     // ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
     if (property->isEnum()) {
         QVariant value = binding->valueAsString(&qmlUnit->header);
-        if (!QQmlPropertyPrivate::write(_qobject, *property, value, context))
-            recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+        bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
+        Q_ASSERT(ok);
+        Q_UNUSED(ok);
         return;
     }
 
@@ -236,109 +237,79 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
     }
     break;
     case QVariant::String: {
-        if (binding->type == QV4::CompiledData::Binding::Type_String) {
-            QString value = binding->valueAsString(&qmlUnit->header);
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: string expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+        QString value = binding->valueAsString(&qmlUnit->header);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::StringList: {
-        if (binding->type == QV4::CompiledData::Binding::Type_String) {
-            QStringList value(binding->valueAsString(&qmlUnit->header));
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+        QStringList value(binding->valueAsString(&qmlUnit->header));
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::ByteArray: {
-        if (binding->type == QV4::CompiledData::Binding::Type_String) {
-            QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+        QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Url: {
-        if (binding->type == QV4::CompiledData::Binding::Type_String) {
-            QString string = binding->valueAsString(&qmlUnit->header);
-            // Encoded dir-separators defeat QUrl processing - decode them first
-            string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
-            QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
-            // Apply URL interceptor
-            if (engine->urlInterceptor())
-                value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: url expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+        QString string = binding->valueAsString(&qmlUnit->header);
+        // Encoded dir-separators defeat QUrl processing - decode them first
+        string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+        QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
+        // Apply URL interceptor
+        if (engine->urlInterceptor())
+            value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::UInt: {
-        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-            double d = binding->valueAsNumber();
-            if (double(uint(d)) == d) {
-                uint value = uint(d);
-                argv[0] = &value;
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-                break;
-            }
-        }
-        recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+        double d = binding->valueAsNumber();
+        uint value = uint(d);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+        break;
     }
     break;
     case QVariant::Int: {
-        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-            double d = binding->valueAsNumber();
-            if (double(int(d)) == d) {
-                int value = int(d);
-                argv[0] = &value;
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-                break;
-            }
-        }
-        recordError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+        double d = binding->valueAsNumber();
+        int value = int(d);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+        break;
     }
     break;
     case QMetaType::Float: {
-        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-            float value = float(binding->valueAsNumber());
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+        float value = float(binding->valueAsNumber());
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Double: {
-        if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-            double value = binding->valueAsNumber();
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: number expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+        double value = binding->valueAsNumber();
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Color: {
         bool ok = false;
         uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
-
-        if (ok) {
-            struct { void *data[4]; } buffer;
-            if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
-                argv[0] = reinterpret_cast<void *>(&buffer);
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            }
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+        Q_ASSERT(ok);
+        struct { void *data[4]; } buffer;
+        if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
+            argv[0] = reinterpret_cast<void *>(&buffer);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
         }
     }
     break;
@@ -346,111 +317,81 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
     case QVariant::Date: {
         bool ok = false;
         QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: date expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Time: {
         bool ok = false;
         QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: time expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::DateTime: {
         bool ok = false;
         QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
 #endif // QT_NO_DATESTRING
     case QVariant::Point: {
         bool ok = false;
         QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::PointF: {
         bool ok = false;
         QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Size: {
         bool ok = false;
         QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::SizeF: {
         bool ok = false;
         QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Rect: {
         bool ok = false;
         QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::RectF: {
         bool ok = false;
         QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
-        if (ok) {
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
-        }
+        Q_ASSERT(ok);
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Bool: {
-        if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
-            bool value = binding->valueAsBoolean();
-            argv[0] = &value;
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
-        }
+        Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+        bool value = binding->valueAsBoolean();
+        argv[0] = &value;
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Vector3D: {
@@ -459,12 +400,11 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
             float yp;
             float zy;
         } vec;
-        if (QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
-            argv[0] = reinterpret_cast<void *>(&vec);
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
-        }
+        bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
+        Q_ASSERT(ok);
+        Q_UNUSED(ok);
+        argv[0] = reinterpret_cast<void *>(&vec);
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::Vector4D: {
@@ -474,74 +414,55 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
             float zy;
             float wp;
         } vec;
-        if (QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
-            argv[0] = reinterpret_cast<void *>(&vec);
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
-        }
+        bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
+        Q_ASSERT(ok);
+        Q_UNUSED(ok);
+        argv[0] = reinterpret_cast<void *>(&vec);
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     case QVariant::RegExp:
-        recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+        Q_ASSERT(!"not possible");
         break;
     default: {
         // generate single literal value assignment to a list property if required
         if (property->propType == qMetaTypeId<QList<qreal> >()) {
-            if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-                QList<qreal> value;
-                value.append(binding->valueAsNumber());
-                argv[0] = reinterpret_cast<void *>(&value);
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            } else {
-                recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected"));
-            }
+            Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+            QList<qreal> value;
+            value.append(binding->valueAsNumber());
+            argv[0] = reinterpret_cast<void *>(&value);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
             break;
         } else if (property->propType == qMetaTypeId<QList<int> >()) {
-            if (binding->type == QV4::CompiledData::Binding::Type_Number) {
-                double n = binding->valueAsNumber();
-                if (double(int(n)) == n) {
-                    QList<int> value;
-                    value.append(int(n));
-                    argv[0] = reinterpret_cast<void *>(&value);
-                    QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-                    break;
-                } else {
-                    recordError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected"));
-                }
-            }
+            Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+            double n = binding->valueAsNumber();
+            QList<int> value;
+            value.append(int(n));
+            argv[0] = reinterpret_cast<void *>(&value);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
             break;
         } else if (property->propType == qMetaTypeId<QList<bool> >()) {
-            if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
-                QList<bool> value;
-                value.append(binding->valueAsBoolean());
-                argv[0] = reinterpret_cast<void *>(&value);
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            } else {
-                recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
-            }
+            Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+            QList<bool> value;
+            value.append(binding->valueAsBoolean());
+            argv[0] = reinterpret_cast<void *>(&value);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
             break;
         } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
-            if (binding->type == QV4::CompiledData::Binding::Type_String) {
-                QString urlString = binding->valueAsString(&qmlUnit->header);
-                QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
-                QList<QUrl> value;
-                value.append(u);
-                argv[0] = reinterpret_cast<void *>(&value);
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            } else {
-                recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
-            }
+            Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+            QString urlString = binding->valueAsString(&qmlUnit->header);
+            QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
+            QList<QUrl> value;
+            value.append(u);
+            argv[0] = reinterpret_cast<void *>(&value);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
             break;
         } else if (property->propType == qMetaTypeId<QList<QString> >()) {
-            if (binding->type == QV4::CompiledData::Binding::Type_String) {
-                QList<QString> value;
-                value.append(binding->valueAsString(&qmlUnit->header));
-                argv[0] = reinterpret_cast<void *>(&value);
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            } else {
-                recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
-            }
+            Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+            QList<QString> value;
+            value.append(binding->valueAsString(&qmlUnit->header));
+            argv[0] = reinterpret_cast<void *>(&value);
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
             break;
         } else if (property->propType == qMetaTypeId<QJSValue>()) {
             QJSValue value;
@@ -564,20 +485,17 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
         // otherwise, try a custom type assignment
         QString stringValue = binding->valueAsString(&qmlUnit->header);
         QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
-        if (converter) {
-            QVariant value = (*converter)(stringValue);
+        Q_ASSERT(converter);
+        QVariant value = (*converter)(stringValue);
 
-            QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
-            if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
-                recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
-                break;
-            }
-
-            argv[0] = value.data();
-            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-        } else {
-            recordError(binding->location, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType))));
+        QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
+        if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
+            recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
+            break;
         }
+
+        argv[0] = value.data();
+        QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
     }
     break;
     }
@@ -635,17 +553,6 @@ void QmlObjectCreator::setupBindings()
 
 bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
 {
-    if (property && !property->isWritable()
-        && !property->isQList()
-        && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
-        && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
-        && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
-        && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
-        ) {
-        recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(property->name(_qobject)));
-        return false;
-    }
-
     if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
         Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
         QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
@@ -679,10 +586,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
 
     QObject *createdSubObject = 0;
     if (binding->type == QV4::CompiledData::Binding::Type_Object) {
-        if (_valueTypeProperty) {
-            recordError(binding->location, tr("Unexpected object assignment"));
-            return false;
-        }
+        Q_ASSERT(!_valueTypeProperty);
         createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
         if (!createdSubObject)
             return false;
@@ -858,33 +762,9 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
             if (_currentList.append)
                 _currentList.append(&_currentList, itemToAdd);
         } else {
-            QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
-
-            // We want to raw metaObject here as the raw metaobject is the
-            // actual property type before we applied any extensions that might
-            // effect the properties on the type, but don't effect assignability
-            QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
-
-            // Will be true if the assgned type inherits propertyMetaObject
-            bool isAssignable = false;
-            // Determine isAssignable value
-            if (propertyMetaObject) {
-                QQmlPropertyCache *c = propertyCaches.value(binding->value.objectIndex);
-                if (!c)
-                    c = enginePrivate->cache(createdSubObject);
-                while (c && !isAssignable) {
-                    isAssignable |= c == propertyMetaObject;
-                    c = c->parent();
-                }
-            }
-
-            if (isAssignable) {
-                argv[0] = &createdSubObject;
-                QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
-            } else {
-                recordError(binding->valueLocation, tr("Cannot assign object to property"));
-                return false;
-            }
+            // pointer compatibility was tested in QQmlPropertyValidator at type compile time
+            argv[0] = &createdSubObject;
+            QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
         }
         return true;
     }
index fade1256b06a0ca897e0026ce92e1bbc38d6166d..0a40e2cde2a552a0adc002e92fc3f3ede9b17dee 100644 (file)
@@ -520,13 +520,11 @@ void tst_qqmllanguage::errors()
 {
     QFETCH(QString, file);
     QFETCH(QString, errorFile);
-    // ### FIXME: re-enable these create "checks" when the new compiler is default and does property binding compatibility tests
-    // in the loader thread.
-//    QFETCH(bool, create);
+    QFETCH(bool, create);
 
     QQmlComponent component(&engine, testFileUrl(file));
 
-    if (/*create && */component.isReady()) {
+    if (create) {
         QObject *object = component.create();
         QVERIFY(object == 0);
     }