slint/tests/helper_components
Nathan Collins f2e5acd261
Add interfaces as a proof-of-concept experimental feature (#10181)
* compiler: Introduce ElementType::Interface

Add a new ElementType variant that will allow us to parse interface
declarations using the existing element parsing code.

The match arms implemented are my best guess based on the context of
the enclosing function and how a global is handled.

* compiler: `interface` is a valid top-level item keyword

A document may contain zero or more interfaces. Interfaces do not
support inheritance.

* compiler: An interface excludes the same content as a global

Verify that an interface cannot have:
- sub elements;
- repeated elements;
- property animations;
- states;
- transitions;
- an init callback declaration;
- an init callback implementation.

* compiler: An interface can have public properties

Warn if private properties are declared.

* compiler: `implements` is a valid keyword

It is treated as an alias for `inherits`, for now.

* compiler: Cannot "implement" non-interface components

The compiler produces an error when the `implements` keyword is used
before a global, component, or builtin type.

The parser doesn't know about this kind of relationship - the
"implements" and "inherits" keywords are just consumed. For now we
just go back and check what the expected relationship type was whilst
constructing an Element.

* compiler: interface properties are exposed

Attempt to verify that the interpreter can see and use properties
declared in an interface that a component implements.

This is an initial proof-of-concept, we will need to come back and add
checks and tests for mixing 'inherits' with 'implements'.

* Move existing interface syntax texts to syntax/interfaces

Group interface related tests in a subdirectory of their own.

* compiler: Add uses specified as valid new component syntax

Allow a new component to specify that it exposes one or more
interfaces via a given child element.

This commit introduces the syntax, we will add the implementation in a
future commit.

* compiler: uses statements expose interface properties from child

For each uses statement, iterate through the interface properties and
create two-way bindings to the property on the specified base
component.

The error cases will be populated in follow-up commit. For now,
demonstrate that the initial concept works.

* compiler: emit errors for invalid interfaces in uses statements

Detect and emit errors where:
- the type specified in a uses statement is not an interface;
- the type specified in a uses statement is unknown;
- the type specified in a uses statement cannot be used in this
  context.

* compiler: emit an error when the child specified in a uses statement does not exist

Add a test case to verify the expected error message.

* compiler: verify that external interfaces can be implemented

Add a test to verify that interfaces from imported modules can be
used.

* compiler: verify that renamed components and interfaces can be used

Add a test case to verify that:
- we can import an interface as another name and re-use it;
- we can import a component that implements a renamed interface and
  use it.

* compiler: verify that the child component implements the interface

For each property in an interface that a child element is expected to
implement, verify that the child has a property with the same name,
type and visibility.

This is easier than attempting to store and match interface names
which may change if the user renames an interface when importing.

* compiler: do not allow interface properties to be overridden

Emit a compile error if the user attempts to declare a property that
would override a property from an interface.

* compiler: do not permit interfaces to be used if they would override an inherited property

Look up the interface property on the base type before allowing a
component to implement the interface.

* compiler: emit an error if a uses statement attempts to override an existing binding

I couldn't figure out a good way to test this - everything I came up
with got caught by the prior check that the property does not already
exist.

* compiler: 'interface', 'implements' and 'uses' are experimental features

Guard these keywords behind the experimental features flag. Slint must
be compiled with the `SLINT_ENABLE_EXPERIMENTAL_FEATURES` environment
variable set to enable these keywords.

* compiler: parse_uses_identifier returns a valid SyntaxKind::UsesIdentifier

Previously we were not creating a DeclaredIdentifier if a syntax error
was encountered. This would cause a panic when
`UsesIdentifier::DeclaredIdentifier()` was called for a node with a
syntax error.

As a result, we can convert `TryFrom<&syntax_nodes::UsesIdentifier>
for UsesStatement` to `From<&syntax_nodes::UsesIdentifier> for
UsesStatement`.

* compiler: simplify `UsesSpecifier -> UsesSpecifierList -> UsesIdentifier` to `UsesSpecifier -> UsesIdentifier`

We don't need to intermediate list object because we only expect a
UsesSpecifier to contain UsesIdentifiers.

* lsp: Ensure that uses statements are not broken

Previously the space between the DeclaredIdentifier and the `from`
keyword was being removed. E.g.:

```slint
component C uses { Foo from bar } { }
```

would become:

```slint
component C uses { Foofrom bar } { }
```

This would cause a syntax error. This no longer happens.

* compiler: ':=' to declare an interface is an error

Previously this was a warning to match the global behaviour. Given
that interfaces are a new feature, make it an error to declare them
using the deprecated ':='.

* compiler: private properties in an interface are an error

It does not make sense to declare an interface with properties that
are not accessible to the user of the interface.

* Update insterface syntax tests

The syntax for declaring an expected diagnostic has changed to include
the span (#9703). Update the interface tests that were added using the
old syntax.

* compiler: check experimental features before emitting more specific interface errors

The `implements` keyword should not be supported if experimental
features are not enabled.

* compiler: Simplify UsesStatement

Only store the `syntax_nodes::UsesIdentifier` and replace the old
members with functions returning the appropriate child node of the
`UsesIdentifier`.

* compiler: clean up ElementType::Interface TODO comment

We cannot instantiate an interface element, so we should not be able
to reach one by recursing into the children of a component.
2025-12-10 10:38:13 +01:00
..
export_globals.slint Use the updater on the tests/helper_components 2024-09-25 15:17:49 +02:00
export_interfaces.slint Add interfaces as a proof-of-concept experimental feature (#10181) 2025-12-10 10:38:13 +01:00
export_structs.slint Use the updater on the tests/helper_components 2024-09-25 15:17:49 +02:00
issue_6651_implicit_export.slint Fix order of exports when adding implicit export 2024-10-25 12:10:40 +02:00
main_window.slint Add export { ... } from "....slint"; syntax. (#5533) 2024-07-03 12:50:40 +02:00
re_export.slint
re_export2.slint Add export { ... } from "....slint"; syntax. (#5533) 2024-07-03 12:50:40 +02:00
re_export_all.slint
test_button.slint Add export { ... } from "....slint"; syntax. (#5533) 2024-07-03 12:50:40 +02:00