• Type: Technical task
    • Status: Open
    • Priority: P2: Important
    • Resolution: Unresolved
    • Fix Version/s: 6.x
    • Component/s: QML: Compiler
    • Labels:


      There are multiple language features [1] and runtime (QQmlEngine/QQmlObjectCreator) related features that have to be supported by the type compiler. In particular:

      QML language (object definitions specifically*) [2]:

      • Import statements are handled by the generic machinery (qmlcompiler library); comments are not interesting at the moment (and they do not map to C++ at all in general)
      • Types
        • Basic/builtin types [3] (mostly related to properties)
        • JavaScript types (unclear whether there are any special ones worthy of attention)
        • Object types (mostly related to object bindings)
      • id attribute
      • Properties
        • attributes must map correctly to the C++ model (some require Q_CLASSINFO in C++)
          • default
          • required
          • readonly
        • special types: `var` (QVariant) and `list` (QQmlListProperty/QQmlListReference)
        • attached properties: correctly instantiated to be accessible in JavaScript
        • group properties: both references and value types must be handled (differences are visible in bindings)
        • private properties (Q_PRIVATE_PROPERTY): internal-only but must be supported (QtQuick uses them extensively)
        • special C++ case (no read method): Q_PROPERTY(QByteArray sampler MEMBER sampler)
      • Aliases
        • methods (read, write, notify/bindable) must forward to the corresponding property methods
        • attributes must be aligned with the corresponding property attributes
        • aliases to private properties
        • aliases to group properties (and properties inside group/attached property)
      • Enums
        • C++ enumerations
        • require special code to be accessible in JavaScript (Q_ENUMS should be enough for the meta-object system)
      • Signals
        • C++ signals marked as Q_SIGNALS
      • Methods/functions
        • call JavaScript code through QQmlEnginePrivate::executeRuntimeFunction()
        • marked as Q_INVOKABLE
        • special attribute: default method (NB: it seems to be deprecated in I001ddf4d7933871977f84a5e012d020fb043cc6?)
      • Inline components
        • terra incognita
        • they define a new type (as if having a separate QML file), so must be handled similarly (extra care should be given to how context hierarchy is handled for them: as for document roots?)
        • they use the compilation unit of the QML file (no separate CU)
        • they support cyclic references but not cyclic instantiations (would it actually work for qmltc? might have to use QQmlComponent wrapping just because of this)
          import QtQuick 2.15
          Item {
            component A : Item {
              property B b // NB: if "b: B {}", it should be a recursion error
            component B : Item {
              property A a
            A {
              b: B { Component.onCompleted: console.log(a) }
        • could be troublesome in the code resolving names to types (e.g. is Foo.Bar an enum.enumerator or an inline component?)
      • Bindings
        • Invalid (noop for compiler)
        • Property value assignments
          • Boolean, Number
          • String
          • Null
          • (in general) support conversions between types; complex cases use QQmlStringConverters
          • (in general) must follow QQmlObjectCreator::setPropertyValue() logic
          • (in general) must be aware of type conversions (e.g. bool -> int, int -> bool, etc.)
        • Translations
          • QV4::CompiledData::Binding::Type_Translation
          • QV4::CompiledData::Binding::Type_TranslationById
          • terra incognita (not addressed at all currently)
        • Generic script bindings on a property
          • call JavaScript code through QQmlEnginePrivate::executeRuntimeFunction()
          • can be bound to both old style and new style properties (notify and bindable respectively)
        • Signal handlers (similar to methods)
          • call JavaScript code through QQmlEnginePrivate::executeRuntimeFunction()
          • marked as Q_SLOT
          • connected to signals
        • Property change handlers
          • call JavaScript code through QQmlEnginePrivate::executeRuntimeFunction()
          • can be "attached" to both old style and new style properties (notify and bindable respectively)
          • can be "attached" to properties of different kinds (private, group, attached, list( ? ))
        • Object bindings
          • implement type hierarchy
        • Bindings on attached properties
          • aggregate bindings for individual attached properties, then recurse to bindings of other types
          • in a nutshell, `this->setBinding` is changed into `this->prop->setBinding`
        • Bindings on group properties
          • aggregate bindings for individual group properties, then recurse to bindings of other types
          • in a nutshell, `this->setBinding` is changed into `this->prop->setBinding`
          • extra care with value types needed (well-defined semantics has to be specified yet: what happens on write if there's a connection, binding, etc.)
        • Bindings with regular expressions
          • See QQmlJSImportVisitor::parseLiteralBinding() for literal regular expressions
          • Non-literal ones can probably be handled as script bindings
        • Intriguing bindings (with more cases in QtDS examples e.g. coffee machine)
              RangeSlider {
                  first.handle.objectName: "rangeslider.first"
                  second.handle.objectName: "rangeslider.second"
      • Singleton objects
        • haven't looked at it much, should require special code generation but nothing to redesign in the compiler/codegen (hopefully)
        • could both come from QML (related to Pragma) or C++
      • Pragmas
        • Singleton: handled via qmldir
        • Strict: unclear if this one needs to be supported
      • Namespaces
        • QML "namespaces" (related mostly to how QML modules are imported)
        • C++ namespaces (a C++ type exposed to QML could be declared inside a namespace; that namespace should be visible and usable by the compiler)
      • Special cases
        • Component.onCompleted and Component.onDestruction
        • Component-wrapped types (require QQmlComponent wrapping in the generated code)
        • C++ singletons (might require some boilerplate)
        • "on" assignments (do not seem to semantically differ from normal binding constructions)
        • `parent` property (unclear whether this is a job of the type compiler or JS engine)

      QML importing related:

      QQmlEngine/runtime and QtQuick related:

      • QQmlContext hierarchy for created types (influences JavaScript lookups - e.g. id, inherited methods)
      • Q_INTERFACES (note that these interfaces are inherited, so each subclass' instance should call the interface methods):
        • QQmlParserStatus (QQuickAnimationController)
        • QQmlPropertyValueInterceptor [4] (QQuickBehavior)
        • QQmlPropertyValueSource [5] (QQuickAbstractAnimation)
        • QQmlFinalizerHook
        • TBD
      • Image providers
        • terra incognita (no additional code is generated at the moment)
      • QQmlObjectCreator::sharedState (has to be available when creating generated types)
        • QQmlObjectCreator::sharedState->finalizeCallbacks (implicitly related to QQmlParserStatus) – replaced by QQmlFinalizerHook (once available)
        • QQmlObjectCreator::sharedState->allJavaScriptObjects (unclear whether these are needed)
        • QQmlObjectCreator::sharedState->componentAttached (related to Component.onCompleted/onDestruction; unclear whether needed)
      • Deferred bindings (terra incognita; a.k.a. deferred properties?)
      • Custom parser types (need to figure whether these should be supported at all - QTBUG-95117)
        • QQmlListModel (QML ListModel)
        • QQmlConnections (QML Connections)
        • QQuickPropertyChanges (QML PropertyChanges)
        • SignalTransition
      • QtQuick concepts
        • Visual parents
        • States
        • Transitions
        • Animations (related to Q_INTERFACES(QQmlPropertyValueSource))
        • Animators
        • Animated sprites
        • (in general) might require extra code generation and care at the compiler level (has to be clarified)
      • Resource loading (local, network, etc.)
        • (in general) might require certain network-related code to be generated (e.g. if there's smth handled by QQmlObjectCreator)
        • terra incognita
        • related to QML language elements, ideally should not require any additional work
      • Object finalization order is as follows:
        • 1) QQmlParserStatus objects are finalized (via componentComplete())
        • 2) QQmlFinalizerHook objects are finalized (via componentFinalized())
        • 3) Component.onComplete attached signals are finalized (in qqmlobjectcreator.cpp via `emit obj->complete()`)
        • (in general) qmltc must ensure this order is preserved. note: within-step order of componentComplete()/componentFinalized()/Component.onCompleted is undefined (so root's componentComplete() might happen before some child's componentComplete()).
        • (in general) simplest solution is to allow componentComplete() to run as part of normal object creation, then generate hardcoded instructions for componentFinalized() [as those are somewhat rare] and Component.onComplete():
          void DocumentRoot::finalize()
            // assume at this point that all componentComplete() are run
            // QQmlFinalizerHooks:
            ((QQmlFinalizerHooks *)this->getRandomChild()->getRandomChild())->componentFinalized();
            // ...
            // Component.onCompleted:
            // ...
      • Elements with unclear usage / support model:
        • QQmlIncubationController
        • QQmlAbstractUrlInterceptor
        • QQmlInstantiationInterrupt
        • QML State (related to PropertyChanges; might require special code generation?)

      Codegen features (not related to the language/runtime but nice-to-haves for the compilation):

      • Generate namespace for the classes (to avoid name collisions)
        • Might be optional (with a --namespace argument for qmltc) or "always on"
      • Generate export macro and use that for each generated type (related to QTBUG-96040)

      (Poorly formatted) comments:

      • Interceptors [4] and property value sources [5] (also test how group/attached properties behave with property value sources) – some very basic support added but more work required
      • Proper QQmlEngine context hierarchy – done; fairly extensive tests exist (NB: new hierarchy is not identical to what QQmlComponent generates but this is intentional)
      • Property aliases – partially done; but: need to ensure aliases mimic all Q_PROPERTY attributes of the origins (as much as type inference allows). one missing feature is RESET support.
      • List properties (and list types?) in various shapes and forms (do we need to handle QQmlJSScope::AccessSemantics::Sequence in any interesting ways?) – partially done for list properties (e.g. object bindings) but it's unclear if there's more depth in it
      • Delegates (apparently the parent of a delegate could be a fairly random thing? e.g. contentItem in ListView): must be correctly constructed despite the shenanigans
      • QQmlComponent-based types (usually handled in a special way by loading the component at runtime through QQmlComponent::create()) – delegates are handled but the rest isn't

      [1]: https://doc.qt.io/qt-6/qtqml-syntax-basics.html
      [2]: https://doc.qt.io/qt-6/qtqml-documents-topic.html
      [3]: https://doc.qt.io/qt-6/qmlbasictypes.html and https://doc.qt.io/qt-6/qtqml-typesystem-basictypes.html
      [4]: https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#property-modifier-types
      [5]: https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html#property-value-sources

      Other useful links:


          Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.



              agolubev Andrei Golubev
              agolubev Andrei Golubev
              2 Vote for this issue
              4 Start watching this issue



                  Gerrit Reviews

                  There are no open Gerrit changes