From 597c39ba62c27e947c9ad0d47f2209cf4fdaa2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Zaragoza=20Cort=C3=A9s?= Date: Thu, 4 Apr 2024 10:32:53 -0700 Subject: [PATCH] Fix to RCA panic when assigning call result to tuple (#1359) This change fixes #1357. --- compiler/qsc_rca/src/core.rs | 52 ++++++----- compiler/qsc_rca/tests/assigns.rs | 144 ++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 20 deletions(-) diff --git a/compiler/qsc_rca/src/core.rs b/compiler/qsc_rca/src/core.rs index 76dde230f9..c3b2d63e90 100644 --- a/compiler/qsc_rca/src/core.rs +++ b/compiler/qsc_rca/src/core.rs @@ -1390,27 +1390,39 @@ impl<'a> Analyzer<'a> { updated_compute_kind } ExprKind::Tuple(assignee_exprs) => { - let ExprKind::Tuple(value_exprs) = &value_expr.kind else { - panic!("expected a tuple"); - }; - assert!(assignee_exprs.len() == value_exprs.len()); - - // To determine the update compute kind, we aggregate the runtime features of each element. - let default_value_kind = ValueKind::new_static_from_type(&value_expr.ty); - let mut updated_compute_kind = ComputeKind::Classical; - for (element_assignee_expr_id, element_value_expr_id) in - assignee_exprs.iter().zip(value_exprs.iter()) - { - let element_update_compute_kind = self.update_locals_compute_kind( - *element_assignee_expr_id, - *element_value_expr_id, - ); - updated_compute_kind = updated_compute_kind.aggregate_runtime_features( - element_update_compute_kind, - default_value_kind, - ); + if let ExprKind::Tuple(value_exprs) = &value_expr.kind { + assert!(assignee_exprs.len() == value_exprs.len()); + + // To determine the update compute kind, we aggregate the runtime features of each element. + let default_value_kind = ValueKind::new_static_from_type(&value_expr.ty); + let mut updated_compute_kind = ComputeKind::Classical; + for (element_assignee_expr_id, element_value_expr_id) in + assignee_exprs.iter().zip(value_exprs.iter()) + { + let element_update_compute_kind = self.update_locals_compute_kind( + *element_assignee_expr_id, + *element_value_expr_id, + ); + updated_compute_kind = updated_compute_kind.aggregate_runtime_features( + element_update_compute_kind, + default_value_kind, + ); + } + updated_compute_kind + } else { + // To determine the update compute kind, we aggregate the runtime features of each update. + let default_value_kind = ValueKind::new_static_from_type(&value_expr.ty); + let mut updated_compute_kind = ComputeKind::Classical; + for element_assignee_expr_id in assignee_exprs { + let element_update_compute_kind = self + .update_locals_compute_kind(*element_assignee_expr_id, value_expr_id); + updated_compute_kind = updated_compute_kind.aggregate_runtime_features( + element_update_compute_kind, + default_value_kind, + ); + } + updated_compute_kind } - updated_compute_kind } _ => panic!("expected a local variable or a tuple"), } diff --git a/compiler/qsc_rca/tests/assigns.rs b/compiler/qsc_rca/tests/assigns.rs index 76d30555a6..98f4bdf34d 100644 --- a/compiler/qsc_rca/tests/assigns.rs +++ b/compiler/qsc_rca/tests/assigns.rs @@ -132,3 +132,147 @@ fn check_rca_for_dynamic_double_assign_to_local() { ], ); } + +#[test] +fn chec_rca_for_assign_call_result_to_tuple_of_vars() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + function Foo() : (Int, Int) { + return (1,2); + } + mutable a = 1; + mutable b = 2; + set (a, b) = Foo(); + "#, + ); + let package_store_compute_properties = compilation_context.get_compute_properties(); + check_last_statement_compute_properties( + package_store_compute_properties, + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Classical + dynamic_param_applications: "#]], + ); +} + +#[test] +fn chec_rca_for_assign_var_binded_to_call_result_to_tuple_of_vars() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + function Foo() : (Int, Int) { + return (1,2); + } + let x = Foo(); + mutable a = 1; + mutable b = 2; + set (a, b) = x; + "#, + ); + let package_store_compute_properties = compilation_context.get_compute_properties(); + check_last_statement_compute_properties( + package_store_compute_properties, + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Classical + dynamic_param_applications: "#]], + ); +} + +#[test] +fn chec_rca_for_assign_tuple_var_to_tuple_of_vars() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + let x = (1, (2, 3)); + mutable a = 4; + mutable b = (5, 6); + set (a, b) = x; + "#, + ); + let package_store_compute_properties = compilation_context.get_compute_properties(); + check_last_statement_compute_properties( + package_store_compute_properties, + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Classical + dynamic_param_applications: "#]], + ); +} + +#[test] +fn check_rca_for_assign_classical_call_result_to_tuple_of_vars() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + function Foo(a : Int, b : Int) : (Int, Int) { + return (b, a); + } + mutable a = 1; + mutable b = 2; + set (a, b) = Foo(a, b); + a + "#, + ); + check_last_statement_compute_properties( + compilation_context.get_compute_properties(), + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Classical + dynamic_param_applications: "#]], + ); + compilation_context.update( + r#" + b + "#, + ); + check_last_statement_compute_properties( + compilation_context.get_compute_properties(), + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Classical + dynamic_param_applications: "#]], + ); +} + +#[test] +fn check_rca_for_assign_dynamic_call_result_to_tuple_of_vars() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + function Foo(a : Int, b : Int) : (Int, Int) { + return (b, a); + } + use q = Qubit(); + let r = MResetZ(q); + mutable a = r == Zero ? 0 | 1; + mutable b = 2; + set (a, b) = Foo(a, b); + a + "#, + ); + check_last_statement_compute_properties( + compilation_context.get_compute_properties(), + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Quantum: QuantumProperties: + runtime_features: RuntimeFeatureFlags(UseOfDynamicBool | UseOfDynamicInt) + value_kind: Element(Dynamic) + dynamic_param_applications: "#]], + ); + compilation_context.update( + r#" + b + "#, + ); + check_last_statement_compute_properties( + compilation_context.get_compute_properties(), + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Quantum: QuantumProperties: + runtime_features: RuntimeFeatureFlags(UseOfDynamicBool | UseOfDynamicInt) + value_kind: Element(Dynamic) + dynamic_param_applications: "#]], + ); +}