diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2023-02-16 10:54:34 +0100 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-03-03 12:02:00 +0100 |
| commit | 05f56d7c78754855c643470ad4e8dfd35c96f927 (patch) | |
| tree | fe23c5afec83efd75f06046bc0fdb7b7da465999 /src/qml/jsruntime/qv4runtime.cpp | |
| parent | e625e39845ccecda871659a8ff39ac081f4aee82 (diff) | |
QML: Allow as-casting to value types
If the "Addressable" option to ValueTypeBehavior is set, you can use the
"as" operator to cast a previously unknown type into either undefined
or the given type. We can use this in qmlcachegen to generate efficient
code for further operations on the same type.
In the generated C++ it in fact only works for GetLookup because:
a, We generally don't do SetLookup on value types, yet.
b, We generally don't call methods on value types, yet.
c, We cannot store a union of undefined and a sequence type, yet.
However, getting properties of value types is the most important
application of the new casts so this is well worth it.
As a side effect we can also look up things in potentially undefined
results of other operations now. For example list lookups.
Task-number: QTBUG-94807
Change-Id: Ifdf34f1f3f67b7a0a8953b9ed0e947b74638a28c
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4runtime.cpp')
| -rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index aa4d5c875a..c7ee35b810 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -329,7 +329,7 @@ ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *funct } } -QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval) +static QV4::ReturnedValue doInstanceof(ExecutionEngine *engine, const Value &lval, const Value &rval) { // 11.8.6, 5: rval must be an Object const Object *rhs = rval.as<Object>(); @@ -345,26 +345,48 @@ QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Valu Scope scope(engine); ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance())); if (hasInstance->isUndefined()) - return rhs->instanceOf(lval); + return Encode(rhs->instanceOf(lval)); + FunctionObject *fHasInstance = hasInstance->as<FunctionObject>(); if (!fHasInstance) return engine->throwTypeError(); - ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1)); + return Encode(fHasInstance->call(&rval, &lval, 1)); +} + +QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval) +{ + Scope scope(engine); + ScopedValue result(scope, doInstanceof(engine, lval, rval)); return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean()); } QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval, const Value &rval) { Scope scope(engine); - ScopedValue result(scope, Runtime::Instanceof::call(engine, lval, rval)); + ScopedValue result(scope, doInstanceof(engine, lval, rval)); - if (scope.hasException()) + if (scope.hasException()) { + // "foo instanceof valueType" must not throw an exception. + // So this can only be an object type. engine->catchException(); - else if (result->toBoolean()) + return Encode::null(); + } + + if (result->toBoolean()) return lval.asReturnedValue(); + else if (result->isBoolean()) + return Encode::null(); - return Encode::null(); + // Try to convert the value type + if (Scoped<QQmlTypeWrapper> typeWrapper(scope, rval); typeWrapper) { + const QMetaType metaType = typeWrapper->d()->type().typeId(); + const QVariant result = engine->toVariant(lval, metaType); + if (result.metaType() == metaType) + return engine->metaTypeToJS(metaType, result.constData()); + } + + return Encode::undefined(); } QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right) |
