mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 05:14:48 +00:00
Fix casting with conditional expressions
The following scenario would fail compiling to C++ because we failed to determine the return type of the conditional expression: Test := Rectangle { property<bool> condition; property<color> extra_color; color: condition ? root.extra_color : 4289374890; } The type of the true branch would be color and the false branch would be a float. Since they "disagree", ty() on the expression would return Type::Invalid. This was temporarily worked around in the C++ generator by always returning the type of the true branch, but that's wrong. Instead this patch changes maybe_convert_to to apply the Cast expression to the individual branches, placing the cast only to the numberic literal and correcting the return value of ty() on the conditional expression.
This commit is contained in:
parent
0d4f370e95
commit
03bef6dba3
4 changed files with 52 additions and 18 deletions
|
@ -1,5 +1,5 @@
|
||||||
use crate::object_tree::*;
|
use crate::object_tree::*;
|
||||||
use crate::{parser::SyntaxNode, typeregister::Type};
|
use crate::{diagnostics::Diagnostics, parser::Spanned, parser::SyntaxNode, typeregister::Type};
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use std::rc::Weak;
|
use std::rc::Weak;
|
||||||
|
|
||||||
|
@ -167,4 +167,48 @@ impl Expression {
|
||||||
Expression::Condition { .. } => false,
|
Expression::Condition { .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cast_boxed(self: Box<Self>, target_type: Type) -> Box<Expression> {
|
||||||
|
Box::new(Expression::Cast { from: self, to: target_type })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a conversion node if needed, or throw an error if the type is not matching
|
||||||
|
pub fn maybe_convert_to(
|
||||||
|
self,
|
||||||
|
target_type: Type,
|
||||||
|
node: &SyntaxNode,
|
||||||
|
diag: &mut Diagnostics,
|
||||||
|
) -> Expression {
|
||||||
|
match self {
|
||||||
|
Expression::Condition { condition, true_expr, false_expr } => {
|
||||||
|
let true_expr = if true_expr.ty() != target_type {
|
||||||
|
true_expr.cast_boxed(target_type.clone())
|
||||||
|
} else {
|
||||||
|
true_expr
|
||||||
|
};
|
||||||
|
let false_expr = if false_expr.ty() != target_type {
|
||||||
|
false_expr.cast_boxed(target_type)
|
||||||
|
} else {
|
||||||
|
false_expr
|
||||||
|
};
|
||||||
|
Expression::Condition { condition, true_expr, false_expr }
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let ty = self.ty();
|
||||||
|
if ty == target_type {
|
||||||
|
self
|
||||||
|
} else if ty.can_convert(&target_type) {
|
||||||
|
Expression::Cast { from: Box::new(self), to: target_type }
|
||||||
|
} else if ty == Type::Invalid {
|
||||||
|
self
|
||||||
|
} else {
|
||||||
|
diag.push_error(
|
||||||
|
format!("Cannot convert {} to {}", ty, target_type),
|
||||||
|
node.span(),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,7 @@ fn compile_expression(e: &crate::expression_tree::Expression) -> String {
|
||||||
let false_code = compile_expression(false_expr);
|
let false_code = compile_expression(false_expr);
|
||||||
format!(
|
format!(
|
||||||
r#"[&]() -> {} {{ if ({}) {{ return {}; }} else {{ return {}; }}}}()"#,
|
r#"[&]() -> {} {{ if ({}) {{ return {}; }} else {{ return {}; }}}}()"#,
|
||||||
true_expr.ty().cpp_type().unwrap(),
|
e.ty().cpp_type().unwrap(),
|
||||||
cond_code,
|
cond_code,
|
||||||
true_code,
|
true_code,
|
||||||
false_code
|
false_code
|
||||||
|
|
|
@ -82,7 +82,7 @@ impl Expression {
|
||||||
node.child_node(SyntaxKind::CodeBlock).map(|c| Self::from_codeblock_node(c, ctx))
|
node.child_node(SyntaxKind::CodeBlock).map(|c| Self::from_codeblock_node(c, ctx))
|
||||||
})
|
})
|
||||||
.unwrap_or(Self::Invalid);
|
.unwrap_or(Self::Invalid);
|
||||||
maybe_convert_to(e, ctx, &node)
|
e.maybe_convert_to(ctx.property_type.clone(), &node, &mut ctx.diag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_codeblock_node(node: SyntaxNode, ctx: &mut LookupCtx) -> Expression {
|
fn from_codeblock_node(node: SyntaxNode, ctx: &mut LookupCtx) -> Expression {
|
||||||
|
@ -349,21 +349,6 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a conversion node if needed, or throw an error if the type is not matching
|
|
||||||
fn maybe_convert_to(e: Expression, ctx: &mut LookupCtx, node: &SyntaxNode) -> Expression {
|
|
||||||
let ty = e.ty();
|
|
||||||
if ty == ctx.property_type {
|
|
||||||
e
|
|
||||||
} else if ty.can_convert(&ctx.property_type) {
|
|
||||||
Expression::Cast { from: Box::new(e), to: ctx.property_type.clone() }
|
|
||||||
} else if ty == Type::Invalid {
|
|
||||||
e
|
|
||||||
} else {
|
|
||||||
ctx.diag.push_error(format!("Cannot convert {} to {}", ty, ctx.property_type), node.span());
|
|
||||||
e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unescape_string(string: &str) -> Option<String> {
|
fn unescape_string(string: &str) -> Option<String> {
|
||||||
if !string.starts_with('"') || !string.ends_with('"') {
|
if !string.starts_with('"') || !string.ends_with('"') {
|
||||||
return None;
|
return None;
|
||||||
|
|
5
tests/cases/cast_conditional.60
Normal file
5
tests/cases/cast_conditional.60
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Test := Rectangle {
|
||||||
|
property<bool> condition;
|
||||||
|
property<color> extra_color;
|
||||||
|
color: condition ? root.extra_color : 4289374890;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue