// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
// Conformance validation for `implement I <=> self`: the element must itself declare (or inherit)
// every member of `I` with a matching type, visibility and purity.
interface ValidInterface {
in-out property <int> value;
callback speak();
public function reset();
}
interface OutOnlyInterface {
out property <int> count;
}
interface Inverter {
pure callback invert(bool) -> bool;
}
interface Calculator {
public pure function add(a: int, b: int) -> int;
public function format(value: int) -> string;
public function reset();
in-out property <int> value;
callback notify();
}
// A correct self-implementation compiles cleanly, including satisfying a member via a two-way binding.
export component CorrectImpl {
implement ValidInterface <=> self;
in-out property <int> backing: 24;
in-out property <int> value <=> self.backing;
callback speak();
public function reset() {
self.backing = 0;
}
}
export component CorrectCalculator {
implement Calculator <=> self;
in-out property <int> value;
callback notify();
// The function is correct even though the parameter names differ
pure public function add(x: int, y: int) -> int {
return x + y;
}
public function format(value: int) -> string {
return "Value: " + value;
}
public function reset() {
self.value = 0;
}
}
// Missing members - property, callback and function each report distinctly.
export component MissingProperty {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- missing 'in-out property <int> value;'}
callback speak();
public function reset() {}
}
export component MissingCallback {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- missing 'callback speak();'}
in-out property <int> value;
public function reset() {}
}
export component MissingFunction {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- missing 'pure public function add(int, int) -> int { }'}
in-out property <int> value;
callback notify();
public function format(value: int) -> string {
return "";
}
public function reset() {}
}
// Locally declared members with the wrong type / visibility / purity.
export component IncorrectPropertyType {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- 'value' must be a 'int' property (found a 'float' property)}
in-out property <float> value;
// > <note{'IncorrectPropertyType' declares 'value' here, 'ValidInterface' expects 'in-out property <int> value;'}
callback speak();
public function reset() {}
}
export component IncorrectCallbackType {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- 'speak' must be 'callback speak();' (found 'callback speak(string);')}
in-out property <int> value;
callback speak(string);
// > <note{'IncorrectCallbackType' declares 'speak' here, 'ValidInterface' expects 'callback speak();'}
public function reset() {}
}
export component IncorrectPropertyVisibility {
implement OutOnlyInterface <=> self;
// > <error{Cannot implement 'OutOnlyInterface'.↵- 'count' must be 'out' (found 'in-out')}
// Intentionally use `in_out` to verify that keywords with underscores are correctly normalized.
in_out property <int> count;
// > <note{'IncorrectPropertyVisibility' declares 'count' here, 'OutOnlyInterface' expects 'out property <int> count;'}
}
interface ImpureFunctionInterface {
public function bar(i: int, s: string) -> bool;
}
export component IncorrectCallbackPurity {
implement Inverter <=> self;
// > <error{Cannot implement 'Inverter'.↵- 'invert' must be 'pure'}
implement ImpureFunctionInterface <=> self;
callback invert(bool) -> bool;
// > <note{'IncorrectCallbackPurity' declares 'invert' here, 'Inverter' expects 'pure callback invert(bool) -> bool;'}
// Implementation is pure, interface is not - this should not raise an error
public pure function bar(i: int, s: string) -> bool {
return false;
}
}
// Function mismatches: purity, visibility, arguments and return type.
export component ImpureFunction {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'add' must be 'pure'}
in-out property <int> value;
callback notify();
public function add(a: int, b: int) -> int {
// > <note{'ImpureFunction' declares 'add' here, 'Calculator' expects 'pure public function add(int, int) -> int { }'}
return a + b;
}
public function format(value: int) -> string {
return "";
}
public function reset() {}
}
export component IncorrectFunctionArguments {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'format' must be 'public function format(int) -> string { }' (found 'public function format(string, int) -> string { }')}
in-out property <int> value;
callback notify();
pure public function add(a: int, b: int) -> int {
return a + b;
}
public function format(fmt: string, value: int) -> string {
// > <note{'IncorrectFunctionArguments' declares 'format' here, 'Calculator' expects 'public function format(int) -> string { }'}
return "";
}
public function reset() {}
}
// Too few arguments: there is no offending argument to point at, so the note falls back to the name.
export component MissingFunctionArguments {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'add' must be 'pure public function add(int, int) -> int { }' (found 'pure public function add(int) -> int { }')}
in-out property <int> value;
callback notify();
pure public function add(a: int) -> int {
// > <note{'MissingFunctionArguments' declares 'add' here, 'Calculator' expects 'pure public function add(int, int) -> int { }'}
return a;
}
public function format(value: int) -> string {
return "";
}
public function reset() {}
}
export component IncorrectFunctionReturnType {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'format' must be 'public function format(int) -> string { }' (found 'public function format(int) { }')}
in-out property <int> value;
callback notify();
pure public function add(a: int, b: int) -> int {
return a + b;
}
public function format(value: int) {
// > <note{'IncorrectFunctionReturnType' declares 'format' here, 'Calculator' expects 'public function format(int) -> string { }'}
}
public function reset() {}
}
export component IncorrectFunctionVisibility {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'reset' must be 'public' (found 'protected')}
in-out property <int> value;
callback notify();
pure public function add(a: int, b: int) -> int {
return a + b;
}
public function format(value: int) -> string {
return "";
}
protected function reset() {}
// > <note{'IncorrectFunctionVisibility' declares 'reset' here, 'Calculator' expects 'public function reset() { }'}
}
// A member name resolving to the wrong kind (function name declared as a property / callback).
export component CannotOverrideFunction {
implement Calculator <=> self;
// > <error{Cannot implement 'Calculator'.↵- 'format' must be 'public function format(int) -> string { }' (found a 'string' property)↵- 'reset' must be 'public function reset() { }' (found 'callback reset();')}
in-out property <int> value;
callback notify();
pure public function add(a: int, b: int) -> int {
return a + b;
}
in property <string> format;
// > <note{'CannotOverrideFunction' declares 'format' here, 'Calculator' expects 'public function format(int) -> string { }'}
callback reset();
// > <note{'CannotOverrideFunction' declares 'reset' here, 'Calculator' expects 'public function reset() { }'}
}
// Conflicts with an inherited (non-local) member: property, callback and function variants.
component BaseWithMembers {
in-out property <float> value;
// > <note{'BaseWithMembers' declares 'value' here, 'ValidInterface' expects 'in-out property <int> value;'}
callback speak(string);
// > <note{'BaseWithMembers' declares 'speak' here, 'ValidInterface' expects 'callback speak();'}
public function reset() {}
@children
}
export component DerivedConflicts inherits BaseWithMembers {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- 'speak' must be 'callback speak();' (found 'callback speak(string);')↵- 'value' must be a 'int' property (found a 'float' property)}
}
interface CallbackInterface {
callback action();
}
component BaseWithFunction {
public function action() {}
// > <note{'BaseWithFunction' declares 'action' here, 'CallbackInterface' expects 'callback action();'}
@children
}
export component ImplementFunctionConflict inherits BaseWithFunction {
implement CallbackInterface <=> self;
// > <error{Cannot implement 'CallbackInterface'.↵- 'action' must be 'callback action();' (found 'public function action() { }')}
}
// Each member declared as the wrong kind of member.
export component CrossKindMismatch {
implement ValidInterface <=> self;
// > <error{Cannot implement 'ValidInterface'.↵- 'reset' must be 'public function reset() { }' (found a 'int' property)↵- 'speak' must be 'callback speak();' (found a 'int' property)↵- 'value' must be 'in-out property <int> value;' (found 'callback value();')}
callback value();
// > <note{'CrossKindMismatch' declares 'value' here, 'ValidInterface' expects 'in-out property <int> value;'}
in-out property <int> speak;
// > <note{'CrossKindMismatch' declares 'speak' here, 'ValidInterface' expects 'callback speak();'}
in-out property <int> reset;
// > <note{'CrossKindMismatch' declares 'reset' here, 'ValidInterface' expects 'public function reset() { }'}
}
// A single member that violates several constraints at once, joined into one message.
export component MultipleViolations {
implement OutOnlyInterface <=> self;
// > <error{Cannot implement 'OutOnlyInterface'.↵- 'count' must be a 'int' property (found a 'float' property)↵- 'count' must be 'out' (found 'in-out')}
in-out property <float> count;
// > <note{'MultipleViolations' declares 'count' here, 'OutOnlyInterface' expects 'out property <int> count;'}
// > <^note{'MultipleViolations' declares 'count' here, 'OutOnlyInterface' expects 'out property <int> count;'}
}
interface Viewport {
in-out property <float> viewport-x;
in-out property <float> viewport-y;
}
// The Viewport interface properties conflict with the properties on the built-in Flickable component
export component ConflictsWithBuiltIn inherits Flickable {
implement Viewport <=> self;
// > <error{Cannot implement 'Viewport'.↵- 'viewport-x' must be a 'float' property (found a 'length' property)↵- 'viewport-y' must be a 'float' property (found a 'length' property)}
}