diff --git a/sixtyfps_compiler/expression_tree.rs b/sixtyfps_compiler/expression_tree.rs index 0535cd2ea..bac6f5a84 100644 --- a/sixtyfps_compiler/expression_tree.rs +++ b/sixtyfps_compiler/expression_tree.rs @@ -1,5 +1,5 @@ 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 std::rc::Weak; @@ -167,4 +167,48 @@ impl Expression { Expression::Condition { .. } => false, } } + + pub fn cast_boxed(self: Box, target_type: Type) -> Box { + 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 + } + } + } + } } diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index e1d4c1160..2560427ad 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -377,7 +377,7 @@ fn compile_expression(e: &crate::expression_tree::Expression) -> String { let false_code = compile_expression(false_expr); format!( r#"[&]() -> {} {{ if ({}) {{ return {}; }} else {{ return {}; }}}}()"#, - true_expr.ty().cpp_type().unwrap(), + e.ty().cpp_type().unwrap(), cond_code, true_code, false_code diff --git a/sixtyfps_compiler/passes/resolving.rs b/sixtyfps_compiler/passes/resolving.rs index fda307a1c..1b113c171 100644 --- a/sixtyfps_compiler/passes/resolving.rs +++ b/sixtyfps_compiler/passes/resolving.rs @@ -82,7 +82,7 @@ impl Expression { node.child_node(SyntaxKind::CodeBlock).map(|c| Self::from_codeblock_node(c, ctx)) }) .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 { @@ -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 { if !string.starts_with('"') || !string.ends_with('"') { return None; diff --git a/tests/cases/cast_conditional.60 b/tests/cases/cast_conditional.60 new file mode 100644 index 000000000..785b392a9 --- /dev/null +++ b/tests/cases/cast_conditional.60 @@ -0,0 +1,5 @@ +Test := Rectangle { + property condition; + property extra_color; + color: condition ? root.extra_color : 4289374890; +}