Add support for assigning literal value to sequence property
authorChris Adams <christopher.adams@nokia.com>
Wed, 2 Nov 2011 00:21:37 +0000 (10:21 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 1 Dec 2011 01:40:06 +0000 (02:40 +0100)
It is a language semantic that we allow clients to assign a single
value to a sequence/list property (assuming that the types match).
Now that we support sequence types, this commit adds support for
this semantic by determining whether the built-in type of the literal
corresponds to the associated sequence (eg, int for QList<int>, qreal
for QList<qreal>, bool for QList<bool>, QString for QStringList etc).

Similarly, some value types can be constructed from literal string
values (via string converters) and these need to be handled also.

Task-number: QTBUG-18062
Task-number: QTBUG-21770
Change-Id: Iacd91b2af122cd8f20b7df2fa6056a7d7c52bf53
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>

12 files changed:
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativeinstruction.cpp
src/declarative/qml/qdeclarativeinstruction_p.h
src/declarative/qml/qdeclarativeproperty.cpp
src/declarative/qml/qdeclarativevme.cpp
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

index 9b80c2c..3b47e20 100644 (file)
 #include <QtCore/qdebug.h>
 #include <QtCore/qdatetime.h>
 
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+
 QT_BEGIN_NAMESPACE
 
 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
@@ -235,6 +241,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p
         case QVariant::String:
             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
             break;
+        case QVariant::StringList: // we expect a string literal.  A string list is not a literal assignment.
+            if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
+            break;
         case QVariant::ByteArray:
             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
             break;
@@ -344,6 +353,41 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p
             break;
         default:
             {
+            // check if assigning a literal value to a list property.
+            // in each case, check the singular, since an Array of the specified type
+            // will not go via this literal assignment codepath.
+            if (type == qMetaTypeId<QList<qreal> >()) {
+                if (!v->value.isNumber()) {
+                    COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
+                }
+                break;
+            } else if (type == qMetaTypeId<QList<int> >()) {
+                bool ok = v->value.isNumber();
+                if (ok) {
+                    double n = v->value.asNumber();
+                    if (double(int(n)) != n)
+                        ok = false;
+                }
+                if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
+                break;
+            } else if (type == qMetaTypeId<QList<bool> >()) {
+                if (!v->value.isBoolean()) {
+                    COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
+                }
+                break;
+            } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal.  A string list is not a literal assignment.
+                if (!v->value.isString()) {
+                    COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
+                }
+                break;
+            } else if (type == qMetaTypeId<QList<QUrl> >()) {
+                if (!v->value.isString()) {
+                    COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
+                }
+                break;
+            }
+
+            // otherwise, check for existence of string converter to custom type
             QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
             if (!converter)
                 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
@@ -440,6 +484,14 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr
             output->addInstruction(instr);
             }
             break;
+        case QVariant::StringList:
+            {
+            Instruction::StoreStringList instr;
+            instr.propertyIndex = prop->index;
+            instr.value = output->indexForString(v->value.asString());
+            output->addInstruction(instr);
+            }
+            break;
         case QVariant::ByteArray:
             {
             Instruction::StoreByteArray instr;
@@ -638,6 +690,43 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr
             break;
         default:
             {
+            // generate single literal value assignment to a list property if required
+            if (type == qMetaTypeId<QList<qreal> >()) {
+                Instruction::StoreDoubleQList instr;
+                instr.propertyIndex = prop->index;
+                instr.value = v->value.asNumber();
+                output->addInstruction(instr);
+                break;
+            } else if (type == qMetaTypeId<QList<int> >()) {
+                Instruction::StoreIntegerQList instr;
+                instr.propertyIndex = prop->index;
+                instr.value = int(v->value.asNumber());
+                output->addInstruction(instr);
+                break;
+            } else if (type == qMetaTypeId<QList<bool> >()) {
+                Instruction::StoreBoolQList instr;
+                bool b = v->value.asBoolean();
+                instr.propertyIndex = prop->index;
+                instr.value = b;
+                output->addInstruction(instr);
+                break;
+            } else if (type == qMetaTypeId<QList<QUrl> >()) {
+                Instruction::StoreUrlQList instr;
+                QString string = v->value.asString();
+                QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
+                instr.propertyIndex = prop->index;
+                instr.value = output->indexForUrl(u);
+                output->addInstruction(instr);
+                break;
+            } else if (type == qMetaTypeId<QList<QString> >()) {
+                Instruction::StoreStringQList instr;
+                instr.propertyIndex = prop->index;
+                instr.value = output->indexForString(v->value.asString());
+                output->addInstruction(instr);
+                break;
+            }
+
+            // otherwise, generate custom type literal assignment
             Instruction::AssignCustomType instr;
             instr.propertyIndex = prop->index;
             instr.primitive = output->indexForString(v->value.asString());
index 5f8b253..da5c290 100644 (file)
@@ -93,21 +93,39 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
     case QDeclarativeInstruction::StoreDouble:
         qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
         break;
+    case QDeclarativeInstruction::StoreDoubleQList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE_QLIST\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+        break;
     case QDeclarativeInstruction::StoreInteger:
         qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
         break;
+    case QDeclarativeInstruction::StoreIntegerQList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER_QLIST\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+        break;
     case QDeclarativeInstruction::StoreBool:
         qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
         break;
+    case QDeclarativeInstruction::StoreBoolQList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_BOOL_QLIST\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+        break;
     case QDeclarativeInstruction::StoreString:
         qWarning().nospace() << idx << "\t\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
         break;
+    case QDeclarativeInstruction::StoreStringList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_STRINGLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+        break;
+    case QDeclarativeInstruction::StoreStringQList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+        break;
     case QDeclarativeInstruction::StoreByteArray:
         qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
         break;
     case QDeclarativeInstruction::StoreUrl:
         qWarning().nospace() << idx << "\t\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
         break;
+    case QDeclarativeInstruction::StoreUrlQList:
+        qWarning().nospace() << idx << "\t\t" << "STORE_URL_QLIST\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
+        break;
     case QDeclarativeInstruction::StoreColor:
         qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
         break;
index d73ce46..b36a664 100644 (file)
@@ -79,12 +79,18 @@ QT_BEGIN_NAMESPACE
     F(StoreVarDouble, storeDouble) \
     F(StoreVarBool, storeBool) \
     F(StoreString, storeString) \
+    F(StoreStringList, storeString) \
+    F(StoreStringQList, storeString) \
     F(StoreByteArray, storeByteArray) \
     F(StoreUrl, storeUrl) \
+    F(StoreUrlQList, storeUrl) \
     F(StoreFloat, storeFloat) \
     F(StoreDouble, storeDouble) \
+    F(StoreDoubleQList, storeDouble) \
     F(StoreBool, storeBool) \
+    F(StoreBoolQList, storeBool) \
     F(StoreInteger, storeInteger) \
+    F(StoreIntegerQList, storeInteger) \
     F(StoreColor, storeColor) \
     F(StoreDate, storeDate) \
     F(StoreTime, storeTime) \
index d6a2776..795283c 100644 (file)
 
 #include <math.h>
 
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+
 QT_BEGIN_NAMESPACE
 
 /*!
@@ -1285,6 +1291,59 @@ bool QDeclarativePropertyPrivate::write(QObject *object,
                 }
             }
         }
+        if (!ok) {
+            // the only other option is that they are assigning a single value
+            // to a sequence type property (eg, an int to a QList<int> property).
+            if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
+                QList<int> list;
+                list << value.toInt();
+                v = QVariant::fromValue<QList<int> >(list);
+                ok = true;
+            } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
+                QList<qreal> list;
+                list << value.toReal();
+                v = QVariant::fromValue<QList<qreal> >(list);
+                ok = true;
+            } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
+                QList<bool> list;
+                list << value.toBool();
+                v = QVariant::fromValue<QList<bool> >(list);
+                ok = true;
+            } else if ((variantType == QVariant::Url || variantType == QVariant::String || variantType == QVariant::ByteArray)
+                       && propertyType == qMetaTypeId<QList<QUrl> >()) {
+                QUrl u;
+                bool found = false;
+                if (variantType == QVariant::Url) {
+                    u = value.toUrl();
+                    found = true;
+                } else if (variantType == QVariant::ByteArray) {
+                    u = QUrl(QString::fromUtf8(value.toByteArray()));
+                    found = true;
+                } else if (variantType == QVariant::String) {
+                    u = QUrl(value.toString());
+                    found = true;
+                }
+                if (!found)
+                    return false;
+                if (context && u.isRelative() && !u.isEmpty())
+                    u = context->resolvedUrl(u);
+                QList<QUrl> list;
+                list << u;
+                v = QVariant::fromValue<QList<QUrl> >(list);
+                ok = true;
+            } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
+                QList<QString> list;
+                list << value.toString();
+                v = QVariant::fromValue<QList<QString> >(list);
+                ok = true;
+            } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
+                QStringList list;
+                list << value.toString();
+                v = QVariant::fromValue<QStringList>(list);
+                ok = true;
+            }
+        }
+
         if (ok) {
             void *a[] = { (void *)v.constData(), 0, &status, &flags};
             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
@@ -1358,6 +1417,10 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object,
         value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
     } else if (result->IsNull() && core.isQObject()) {
         value = QVariant::fromValue((QObject *)0);
+    } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
+        value = v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >());
+        if (value.userType() == qMetaTypeId<QString>())
+            value = QVariant(QUrl(value.toString()));
     } else if (!isVmeProperty) {
         value = v8engine->toVariant(result, type);
     }
index 313d7f1..a6fc8ba 100644 (file)
@@ -624,6 +624,27 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreString)
 
+        QML_BEGIN_INSTR(StoreStringList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QStringList stringlist(PRIMITIVES.at(instr.value));
+            void *a[] = { (void *)&stringlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreStringList)
+
+        QML_BEGIN_INSTR(StoreStringQList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QList<QString> stringqlist;
+            stringqlist.append(PRIMITIVES.at(instr.value));
+            void *a[] = { (void *)&stringqlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreStringQList)
+
         QML_BEGIN_INSTR(StoreByteArray)
             QObject *target = objects.top();
             void *a[] = { (void *)&DATAS.at(instr.value), 0, &status, &flags };
@@ -640,6 +661,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreUrl)
 
+        QML_BEGIN_INSTR(StoreUrlQList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QList<QUrl> urlqlist;
+            urlqlist.append(URLS.at(instr.value));
+            void *a[] = { (void *)&urlqlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreUrlQList)
+
         QML_BEGIN_INSTR(StoreFloat)
             QObject *target = objects.top();
             CLEAN_PROPERTY(target, instr.propertyIndex);
@@ -660,6 +692,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreDouble)
 
+        QML_BEGIN_INSTR(StoreDoubleQList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QList<double> doubleqlist;
+            doubleqlist.append(instr.value);
+            void *a[] = { (void *)&doubleqlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreDoubleQList)
+
         QML_BEGIN_INSTR(StoreBool)
             QObject *target = objects.top();
             CLEAN_PROPERTY(target, instr.propertyIndex);
@@ -669,6 +712,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreBool)
 
+        QML_BEGIN_INSTR(StoreBoolQList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QList<bool> boolqlist;
+            boolqlist.append(instr.value);
+            void *a[] = { (void *)&boolqlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreBoolQList)
+
         QML_BEGIN_INSTR(StoreInteger)
             QObject *target = objects.top();
             CLEAN_PROPERTY(target, instr.propertyIndex);
@@ -678,6 +732,17 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
                                   instr.propertyIndex, a);
         QML_END_INSTR(StoreInteger)
 
+        QML_BEGIN_INSTR(StoreIntegerQList)
+            QObject *target = objects.top();
+            CLEAN_PROPERTY(target, instr.propertyIndex);
+
+            QList<int> intqlist;
+            intqlist.append(instr.value);
+            void *a[] = { (void *)&intqlist, 0, &status, &flags };
+            QMetaObject::metacall(target, QMetaObject::WriteProperty,
+                                  instr.propertyIndex, a);
+        QML_END_INSTR(StoreIntegerQList)
+
         QML_BEGIN_INSTR(StoreColor)
             QObject *target = objects.top();
             CLEAN_PROPERTY(target, instr.propertyIndex);
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml
new file mode 100644 (file)
index 0000000..be283fd
--- /dev/null
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    intListProperty: [1, 2]
+    qrealListProperty: [1.1, 2.2]
+    boolListProperty: [false, true]
+    urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ]
+    stringListProperty: [ "one", "two" ]
+    qstringListProperty: [ "one", "two" ]
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml
new file mode 100644 (file)
index 0000000..c8fb28b
--- /dev/null
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    intListProperty: 1
+    qrealListProperty: 1.1
+    boolListProperty: false
+    urlListProperty: "http://www.example1.com"
+    stringListProperty: "one"
+    qstringListProperty: "two"
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml
new file mode 100644 (file)
index 0000000..ad8a92e
--- /dev/null
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    intListProperty: 1
+    qrealListProperty: 1.1
+    boolListProperty: false
+    urlListProperty: Qt.resolvedUrl("example.html")
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml
new file mode 100644 (file)
index 0000000..a9f2e64
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    Component.onCompleted: {
+        intListProperty = [1, 2]
+        qrealListProperty = [1.1, 2.2]
+        boolListProperty = [false, true]
+        urlListProperty = [ "http://www.example1.com", "http://www.example2.com" ]
+        stringListProperty = [ "one", "two" ]
+        qstringListProperty = [ "one", "two" ]
+    }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml
new file mode 100644 (file)
index 0000000..b8697e4
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    Component.onCompleted: {
+        intListProperty = 1;
+        qrealListProperty = 1.1;
+        boolListProperty = false;
+        urlListProperty = "http://www.example1.com";
+        stringListProperty = "one";
+        qstringListProperty = "two";
+    }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml
new file mode 100644 (file)
index 0000000..7a794eb
--- /dev/null
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+    Component.onCompleted: {
+        intListProperty = 1;
+        qrealListProperty = 1.1;
+        boolListProperty = false;
+        urlListProperty = Qt.resolvedUrl("example.html");
+    }
+}
index 3fdf1e9..52e7661 100644 (file)
@@ -177,8 +177,10 @@ private slots:
     void sequenceConversionThreads();
     void sequenceConversionBindings();
     void sequenceConversionCopy();
+    void assignSequenceTypes();
     void qtbug_22464();
     void qtbug_21580();
+
     void bug1();
     void bug2();
     void dynamicCreationCrash();
@@ -4320,6 +4322,89 @@ void tst_qdeclarativeecmascript::sequenceConversionCopy()
     delete object;
 }
 
+void tst_qdeclarativeecmascript::assignSequenceTypes()
+{
+    // test binding array to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+    delete object;
+    }
+
+    // test binding literal to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+    delete object;
+    }
+
+    // test binding single value to sequence type property
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
+    delete object;
+    }
+
+    // test assigning array to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+    delete object;
+    }
+
+    // test assigning literal to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+    QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+    QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+    delete object;
+    }
+
+    // test assigning single value to sequence type property in js function
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
+    MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+    QVERIFY(object != 0);
+    QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+    QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+    QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+    QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
+    delete object;
+    }
+}
+
 // Test that assigning a null object works 
 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
 void tst_qdeclarativeecmascript::nullObjectBinding()