compiler: Reject comparison on unsupported types

The compiler was accepting the comparison of types such as color, or
struct, and then later we'd get rust compilation error or interpreter
panic.

Example seen in the crash reporter:
`internal/interpreter/eval.rs:257:35`
```
unsupported Value::Brush(SolidColor(Color { red: 0, green: 0, blue: 0, alpha: 0 })) ≤ Value::Brush(SolidColor(Color { red: 255, green: 0, blue: 0, alpha: 255 }))
```

Note that some code hapenned to compile with rust or C++.
For example, comparison of bool, or anonymous struct (represented as
tuples), or color represeted as int)
So technically this is a breaking change.
But this should be fine as this was not working in the interpreter and
this is a bug fix.

ChangeLog: Slint compilation error for comparison of types that can't be
compared with less or greater operator.
This commit is contained in:
Olivier Goffart 2025-05-07 11:39:27 +02:00 committed by GitHub
parent d85f11758c
commit 31867fad61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 1 deletions

View file

@ -999,7 +999,13 @@ impl Expression {
let expected_ty = match operator_class(op) {
OperatorClass::ComparisonOp => {
Self::common_target_type_for_type_list([lhs.ty(), rhs.ty()].iter().cloned())
let ty =
Self::common_target_type_for_type_list([lhs.ty(), rhs.ty()].iter().cloned());
if !matches!(op, '=' | '!') && !ty.as_unit_product().is_some() && ty != Type::String
{
ctx.diag.push_error(format!("Values of type {ty} cannot be compared"), &node);
}
ty
}
OperatorClass::LogicalOp => Type::Bool,
OperatorClass::ArithmeticOp => {

View file

@ -0,0 +1,15 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
export component C {
out property <bool> color-cmp: Colors.red > Colors.blue;
// ^error{Values of type color cannot be compared}
out property <bool> bool-cmp: true > false;
// ^error{Values of type bool cannot be compared}
out property <bool> string-cmp: "eee" > "ddd";
out property <bool> array-cmp: [45] < [45];
// ^error{Values of type \[float\] cannot be compared}
out property <bool> struct-cmp: { foo: 45 } <= { foo: 45 };
// ^error{Values of type \{ foo: float,\} cannot be compared}
}

View file

@ -13,6 +13,10 @@ TestCase := Rectangle {
property<string> my_str: "hello";
property<bool> t7: my_str == "hello";
property<bool> string-cmp: "fooa" < "foob";
out property <bool> test: t1 && !t2 && t3 && t4 && t5 && !t6 && t7 && string-cmp;
}
/*
```cpp
@ -26,6 +30,9 @@ assert_eq(instance.get_t5(), true);
assert_eq(instance.get_t6(), false);
assert_eq(instance.get_t7(), true);
assert_eq(instance.get_string_cmp(), true);
assert_eq(instance.get_test(), true);
instance.set_hello(45);
assert_eq(instance.get_t1(), true);
assert_eq(instance.get_t2(), true);
@ -72,6 +79,9 @@ assert_eq!(instance.get_t5(), true);
assert_eq!(instance.get_t6(), false);
assert_eq!(instance.get_t7(), true);
assert_eq!(instance.get_string_cmp(), true);
assert_eq!(instance.get_test(), true);
instance.set_hello(45);
assert_eq!(instance.get_t1(), true);
assert_eq!(instance.get_t2(), true);
@ -116,6 +126,9 @@ assert.equal(instance.t5, true);
assert.equal(instance.t6, false);
assert.equal(instance.t7, true);
assert.equal(instance.string_cmp, true);
assert.equal(instance.test, true);
instance.hello = 45;
assert.equal(instance.t1, true);
assert.equal(instance.t2, true);