From b85a22a711df4c897a9fa8a74f42ac6146542105 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Tue, 5 Nov 2024 13:37:20 -0800 Subject: [PATCH 1/4] Add eval and cell events (#2004) --- pip/qsharp/_ipython.py | 12 +++++++++++- pip/qsharp/_qsharp.py | 13 +++++++++++-- pip/qsharp/telemetry_events.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/pip/qsharp/_ipython.py b/pip/qsharp/_ipython.py index 1879e48285..2ca3a9b6c3 100644 --- a/pip/qsharp/_ipython.py +++ b/pip/qsharp/_ipython.py @@ -8,10 +8,12 @@ execution within Jupyter notebooks. """ +from time import monotonic from IPython.display import display, Javascript, clear_output from IPython.core.magic import register_cell_magic from ._native import QSharpError from ._qsharp import get_interpreter +from . import telemetry_events import pathlib @@ -30,8 +32,16 @@ def callback(output): # is finished executing. display(display_id=True) + telemetry_events.on_run_cell() + start_time = monotonic() + try: - return get_interpreter().interpret(cell, callback) + results = get_interpreter().interpret(cell, callback) + + durationMs = (monotonic() - start_time) * 1000 + telemetry_events.on_run_cell_end(durationMs) + + return results except QSharpError as e: # pylint: disable=raise-missing-from raise QSharpCellError(str(e)) diff --git a/pip/qsharp/_qsharp.py b/pip/qsharp/_qsharp.py index d901621960..6365e9c40e 100644 --- a/pip/qsharp/_qsharp.py +++ b/pip/qsharp/_qsharp.py @@ -205,7 +205,7 @@ def init( _config = Config(target_profile, language_features, manifest_contents, project_root) # Return the configuration information to provide a hint to the # language service through the cell output. - return _config + return _config def get_interpreter() -> Interpreter: @@ -243,7 +243,15 @@ def callback(output: Output) -> None: pass print(output, flush=True) - return get_interpreter().interpret(source, callback) + telemetry_events.on_eval() + start_time = monotonic() + + results = get_interpreter().interpret(source, callback) + + durationMs = (monotonic() - start_time) * 1000 + telemetry_events.on_eval_end(durationMs) + + return results class ShotResult(TypedDict): @@ -387,6 +395,7 @@ def compile(entry_expr: str) -> QirInputData: telemetry_events.on_compile_end(durationMs, target_profile) return res + def circuit( entry_expr: Optional[str] = None, *, operation: Optional[str] = None ) -> Circuit: diff --git a/pip/qsharp/telemetry_events.py b/pip/qsharp/telemetry_events.py index f4865229db..d31666c55f 100644 --- a/pip/qsharp/telemetry_events.py +++ b/pip/qsharp/telemetry_events.py @@ -58,6 +58,36 @@ def on_run_end(durationMs: float, shots: int) -> None: ) +def on_eval() -> None: + log_telemetry( + "qsharp.eval", + 1, + ) + + +def on_eval_end(durationMs: float) -> None: + log_telemetry( + "qsharp.eval.durationMs", + durationMs, + type="histogram", + ) + + +def on_run_cell() -> None: + log_telemetry( + "qsharp.run.cell", + 1, + ) + + +def on_run_cell_end(durationMs: float) -> None: + log_telemetry( + "qsharp.run.cell.durationMs", + durationMs, + type="histogram", + ) + + def on_compile(profile: str) -> None: log_telemetry("qsharp.compile", 1, properties={"profile": profile}) From c5bd58565809e068eba9b35263ac445c5ae9ce48 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 5 Nov 2024 13:43:03 -0800 Subject: [PATCH 2/4] Avoid flooding iPython display (#2006) This change fixes an issue where the workaround introduced in #1712 for timing in Jupyter cells could cause some environments (notably VS Code) to exceed the 500 item limit on displays and prevent other output from being shown. --- pip/qsharp/_qsharp.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pip/qsharp/_qsharp.py b/pip/qsharp/_qsharp.py index 6365e9c40e..84a083c770 100644 --- a/pip/qsharp/_qsharp.py +++ b/pip/qsharp/_qsharp.py @@ -42,14 +42,12 @@ # Reporting execution time during IPython cells requires that IPython # gets pinged to ensure it understands the cell is active. This is done by -# requesting a display id without displaying any content, avoiding any UI changes -# that would be visible to the user. +# simply importing the display function, which it turns out is enough to begin timing +# while avoiding any UI changes that would be visible to the user. def ipython_helper(): try: if __IPYTHON__: # type: ignore from IPython.display import display - - display(display_id=True) except NameError: pass From 5ac52cd3e105dbdecc26fe93966683f878974b57 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 5 Nov 2024 15:48:15 -0800 Subject: [PATCH 3/4] Skip checking stack frames in evaluator expect tests (#2008) It used to be that we avoided noise in the evaluator tests during libraries edits by avoiding having spans from the stdlib show up in there, but newer tests include calls to `Std.Intrinsic.I` that need spans updated every time something alphabetically above that operation changes in the stdlib. This change updates the expect call on failure to only verify the error and not the stack frames, as call stacks are already verified in other tests and don't need to be checked here. --- compiler/qsc_eval/src/tests.rs | 875 ++++++++++++--------------------- 1 file changed, 322 insertions(+), 553 deletions(-) diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs index 44ac8f0070..ef34c1a74d 100644 --- a/compiler/qsc_eval/src/tests.rs +++ b/compiler/qsc_eval/src/tests.rs @@ -86,7 +86,7 @@ fn check_expr(file: &str, expr: &str, expect: &Expect) { &mut GenericReceiver::new(&mut out), ) { Ok(value) => expect.assert_eq(&value.to_string()), - Err(err) => expect.assert_debug_eq(&err), + Err((err, _)) => expect.assert_debug_eq(&err), } } @@ -408,42 +408,17 @@ fn block_qubit_use_array_invalid_count_expr() { q }"}, &expect![[r#" - ( - UserFail( - "Cannot allocate qubit array with a negative length", - PackageSpan { - package: PackageId( - 0, - ), - span: Span { - lo: 2050, - hi: 2107, - }, + UserFail( + "Cannot allocate qubit array with a negative length", + PackageSpan { + package: PackageId( + 0, + ), + span: Span { + lo: 2050, + hi: 2107, }, - ), - [ - Frame { - span: Span { - lo: 2050, - hi: 2107, - }, - id: StoreItemId { - package: PackageId( - 0, - ), - item: LocalItemId( - 6, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: false, - controlled: 0, - }, - }, - ], + }, ) "#]], ); @@ -552,20 +527,17 @@ fn binop_andl_no_shortcut() { "", r#"true and (fail "Should Fail")"#, &expect![[r#" - ( - UserFail( - "Should Fail", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 10, - hi: 28, - }, + UserFail( + "Should Fail", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 10, + hi: 28, }, - ), - [], + }, ) "#]], ); @@ -582,19 +554,16 @@ fn binop_div_bigint_zero() { "", "12L / 0L", &expect![[r#" - ( - DivZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 6, - hi: 8, - }, + DivZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 6, + hi: 8, }, - ), - [], + }, ) "#]], ); @@ -620,19 +589,16 @@ fn binop_div_int_zero() { "", "12 / 0", &expect![[r#" - ( - DivZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 5, - hi: 6, - }, + DivZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 5, + hi: 6, }, - ), - [], + }, ) "#]], ); @@ -789,20 +755,17 @@ fn binop_exp_bigint_negative_exp() { "", "2L^-3", &expect![[r#" - ( - InvalidNegativeInt( - -3, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 3, - hi: 5, - }, + InvalidNegativeInt( + -3, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 3, + hi: 5, }, - ), - [], + }, ) "#]], ); @@ -814,20 +777,17 @@ fn binop_exp_bigint_too_large() { "", "2L^9_223_372_036_854_775_807", &expect![[r#" - ( - IntTooLarge( - 9223372036854775807, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 3, - hi: 28, - }, + IntTooLarge( + 9223372036854775807, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 3, + hi: 28, }, - ), - [], + }, ) "#]], ); @@ -864,20 +824,17 @@ fn binop_exp_int_negative_exp() { "", "2^-3", &expect![[r#" - ( - InvalidNegativeInt( - -3, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 2, - hi: 4, - }, + InvalidNegativeInt( + -3, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 2, + hi: 4, }, - ), - [], + }, ) "#]], ); @@ -889,20 +846,17 @@ fn binop_exp_int_too_large() { "", "100^50", &expect![[r#" - ( - IntTooLarge( - 50, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 4, - hi: 6, - }, + IntTooLarge( + 50, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 4, + hi: 6, }, - ), - [], + }, ) "#]], ); @@ -1069,19 +1023,16 @@ fn binop_mod_bigint_zero() { "", "12L % 0L", &expect![[r#" - ( - DivZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 6, - hi: 8, - }, + DivZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 6, + hi: 8, }, - ), - [], + }, ) "#]], ); @@ -1103,19 +1054,16 @@ fn binop_mod_int_zero() { "", "12 % 0", &expect![[r#" - ( - DivZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 5, - hi: 6, - }, + DivZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 5, + hi: 6, }, - ), - [], + }, ) "#]], ); @@ -1132,19 +1080,16 @@ fn binop_mod_double_zero() { "", "1.2 % 0.0", &expect![[r#" - ( - DivZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 6, - hi: 9, - }, + DivZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 6, + hi: 9, }, - ), - [], + }, ) "#]], ); @@ -1345,20 +1290,17 @@ fn binop_shl_int_overflow() { "", "1 <<< 64", &expect![[r#" - ( - IntTooLarge( - 64, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 6, - hi: 8, - }, + IntTooLarge( + 64, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 6, + hi: 8, }, - ), - [], + }, ) "#]], ); @@ -1396,20 +1338,17 @@ fn binop_shr_int_overflow() { "", "1 >>> 64", &expect![[r#" - ( - IntTooLarge( - 64, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 6, - hi: 8, - }, + IntTooLarge( + 64, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 6, + hi: 8, }, - ), - [], + }, ) "#]], ); @@ -1521,20 +1460,17 @@ fn fail_expr() { "", r#"fail "This is a failure""#, &expect![[r#" - ( - UserFail( - "This is a failure", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 0, - hi: 24, - }, + UserFail( + "This is a failure", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 0, + hi: 24, }, - ), - [], + }, ) "#]], ); @@ -1546,20 +1482,17 @@ fn fail_shortcut_expr() { "", r#"{ fail "Got Here!"; fail "Shouldn't get here..."; }"#, &expect![[r#" - ( - UserFail( - "Got Here!", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 2, - hi: 18, - }, + UserFail( + "Got Here!", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 2, + hi: 18, }, - ), - [], + }, ) "#]], ); @@ -1706,19 +1639,16 @@ fn array_slice_step_zero_expr() { "", "[1, 2, 3, 4, 5][...0...]", &expect![[r#" - ( - RangeStepZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 16, - hi: 23, - }, + RangeStepZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 16, + hi: 23, }, - ), - [], + }, ) "#]], ); @@ -1730,20 +1660,17 @@ fn array_slice_out_of_range_expr() { "", "[1, 2, 3, 4, 5][0..7]", &expect![[r#" - ( - IndexOutOfRange( - 5, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 16, - hi: 20, - }, + IndexOutOfRange( + 5, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 16, + hi: 20, }, - ), - [], + }, ) "#]], ); @@ -1755,20 +1682,17 @@ fn array_index_negative_expr() { "", "[1, 2, 3][-2]", &expect![[r#" - ( - InvalidIndex( - -2, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 10, - hi: 12, - }, + InvalidIndex( + -2, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 10, + hi: 12, }, - ), - [], + }, ) "#]], ); @@ -1780,20 +1704,17 @@ fn array_index_out_of_range_expr() { "", "[1, 2, 3][4]", &expect![[r#" - ( - IndexOutOfRange( - 4, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 10, - hi: 11, - }, + IndexOutOfRange( + 4, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 10, + hi: 11, }, - ), - [], + }, ) "#]], ); @@ -2052,20 +1973,17 @@ fn update_invalid_index_range_expr() { "", "[1, 2, 3] w/ 7 <- 4", &expect![[r#" - ( - IndexOutOfRange( - 7, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 13, - hi: 14, - }, + IndexOutOfRange( + 7, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 13, + hi: 14, }, - ), - [], + }, ) "#]], ); @@ -2077,20 +1995,17 @@ fn update_invalid_index_negative_expr() { "", "[1, 2, 3] w/ -1 <- 4", &expect![[r#" - ( - InvalidNegativeInt( - -1, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 13, - hi: 15, - }, + InvalidNegativeInt( + -1, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 13, + hi: 15, }, - ), - [], + }, ) "#]], ); @@ -2285,20 +2200,17 @@ fn update_array_with_range_out_of_range_err() { "", "[0, 1, 2, 3] w/ 1..5 <- [10, 11, 12, 13]", &expect![[r#" - ( - IndexOutOfRange( - 4, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 16, - hi: 20, - }, + IndexOutOfRange( + 4, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 16, + hi: 20, }, - ), - [], + }, ) "#]], ); @@ -2310,20 +2222,17 @@ fn update_array_with_range_negative_index_err() { "", "[0, 1, 2, 3] w/ -1..0 <- [10, 11, 12, 13]", &expect![[r#" - ( - InvalidIndex( - -1, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 16, - hi: 21, - }, + InvalidIndex( + -1, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 16, + hi: 21, }, - ), - [], + }, ) "#]], ); @@ -2335,19 +2244,16 @@ fn update_array_with_range_zero_step_err() { "", "[0, 1, 2, 3] w/ ...0... <- [10, 11, 12, 13]", &expect![[r#" - ( - RangeStepZero( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 16, - hi: 23, - }, + RangeStepZero( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 16, + hi: 23, }, - ), - [], + }, ) "#]], ); @@ -2431,20 +2337,17 @@ fn assignupdate_out_of_range_err() { x }"}, &expect![[r#" - ( - IndexOutOfRange( - 4, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 43, - hi: 44, - }, + IndexOutOfRange( + 4, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 43, + hi: 44, }, - ), - [], + }, ) "#]], ); @@ -2460,20 +2363,17 @@ fn assignupdate_expr_negative_index_err() { x }"}, &expect![[r#" - ( - InvalidNegativeInt( - -1, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 43, - hi: 45, - }, + InvalidNegativeInt( + -1, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 43, + hi: 45, }, - ), - [], + }, ) "#]], ); @@ -2650,20 +2550,17 @@ fn assignupdate_expr_using_range_out_of_range_err() { x }"}, &expect![[r#" - ( - IndexOutOfRange( - 4, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 46, - hi: 50, - }, + IndexOutOfRange( + 4, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 46, + hi: 50, }, - ), - [], + }, ) "#]], ); @@ -2679,20 +2576,17 @@ fn assignupdate_expr_using_range_negative_index_err() { x }"}, &expect![[r#" - ( - InvalidNegativeInt( - -1, - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 46, - hi: 51, - }, + InvalidNegativeInt( + -1, + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 46, + hi: 51, }, - ), - [], + }, ) "#]], ); @@ -3058,42 +2952,17 @@ fn call_adjoint_expr() { "#}, "Adjoint Test.Foo()", &expect![[r#" - ( - UserFail( - "Adjoint Implementation", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 185, - hi: 214, - }, - }, - ), - [ - Frame { - span: Span { - lo: 185, - hi: 214, - }, - id: StoreItemId { - package: PackageId( - 2, - ), - item: LocalItemId( - 1, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: true, - controlled: 0, - }, + UserFail( + "Adjoint Implementation", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 185, + hi: 214, }, - ], + }, ) "#]], ); @@ -3122,42 +2991,17 @@ fn call_adjoint_adjoint_expr() { "#}, "Adjoint Adjoint Test.Foo()", &expect![[r#" - ( - UserFail( - "Body Implementation", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 119, - hi: 145, - }, - }, - ), - [ - Frame { - span: Span { - lo: 119, - hi: 145, - }, - id: StoreItemId { - package: PackageId( - 2, - ), - item: LocalItemId( - 1, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: false, - controlled: 0, - }, + UserFail( + "Body Implementation", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 119, + hi: 145, }, - ], + }, ) "#]], ); @@ -3181,42 +3025,17 @@ fn call_adjoint_self_expr() { "#}, "Adjoint Test.Foo()", &expect![[r#" - ( - UserFail( - "Body Implementation", - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 111, - hi: 137, - }, + UserFail( + "Body Implementation", + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 111, + hi: 137, }, - ), - [ - Frame { - span: Span { - lo: 111, - hi: 137, - }, - id: StoreItemId { - package: PackageId( - 2, - ), - item: LocalItemId( - 1, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: true, - controlled: 0, - }, - }, - ], + }, ) "#]], ); @@ -3699,41 +3518,16 @@ fn controlled_operation_with_duplicate_controls_fails() { Controlled I([ctl, ctl], q); }", &expect![[r#" - ( - QubitUniqueness( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 86, - hi: 101, - }, - }, - ), - [ - Frame { - span: Span { - lo: 74, - hi: 101, - }, - id: StoreItemId { - package: PackageId( - 1, - ), - item: LocalItemId( - 134, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: false, - controlled: 1, - }, + QubitUniqueness( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 86, + hi: 101, }, - ], + }, ) "#]], ); @@ -3749,41 +3543,16 @@ fn controlled_operation_with_target_in_controls_fails() { Controlled I([ctl, q], q); }", &expect![[r#" - ( - QubitUniqueness( - PackageSpan { - package: PackageId( - 2, - ), - span: Span { - lo: 86, - hi: 99, - }, - }, - ), - [ - Frame { - span: Span { - lo: 74, - hi: 99, - }, - id: StoreItemId { - package: PackageId( - 1, - ), - item: LocalItemId( - 134, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: false, - controlled: 1, - }, + QubitUniqueness( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 86, + hi: 99, }, - ], + }, ) "#]], ); From 7159856c04380aa517ee92f57f231a854e02c2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Zaragoza=20Cort=C3=A9s?= Date: Wed, 6 Nov 2024 14:25:38 -0800 Subject: [PATCH 4/4] Fix to RCA panic when mapping a tuple input pattern to a non-tuple expression (#2011) This change fixes an RCA panic that occurs when a tuple input pattern maps to a non-tuple expression. --------- Co-authored-by: Mine Starks <16928427+minestarks@users.noreply.github.com> --- compiler/qsc_rca/src/core.rs | 7 +++-- compiler/qsc_rca/src/tests/calls.rs | 43 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/compiler/qsc_rca/src/core.rs b/compiler/qsc_rca/src/core.rs index e505081523..c6d4067afa 100644 --- a/compiler/qsc_rca/src/core.rs +++ b/compiler/qsc_rca/src/core.rs @@ -2515,6 +2515,7 @@ fn map_input_pattern_to_input_expressions( match &pat.kind { PatKind::Bind(_) | PatKind::Discard => vec![expr_id.expr], PatKind::Tuple(pats) => { + // Map each one of the elements in the pattern to an expression in the tuple. let pats = &pats[skip_ahead..]; let expr = package_store.get_expr(expr_id); if let ExprKind::Tuple(exprs) = &expr.kind { @@ -2533,8 +2534,10 @@ fn map_input_pattern_to_input_expressions( } input_param_exprs } else { - assert!(pats.len() == 1); - vec![expr_id.expr] + // All elements in the pattern map to the same expression. + // This is one of the boundaries where we can lose specific information since we are "unpacking" the + // tuple represented by a single expression. + vec![expr_id.expr; pats.len()] } } } diff --git a/compiler/qsc_rca/src/tests/calls.rs b/compiler/qsc_rca/src/tests/calls.rs index b7795d1ef6..899ee410ab 100644 --- a/compiler/qsc_rca/src/tests/calls.rs +++ b/compiler/qsc_rca/src/tests/calls.rs @@ -282,3 +282,46 @@ fn check_rca_for_call_to_operation_with_codegen_intrinsic_override_treated_as_in dynamic_param_applications: "#]], ); } + +#[test] +fn check_rca_for_call_to_function_that_receives_tuple_with_a_non_tuple_classical_argument() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + function Foo() : (Result, Result) { (Zero, Zero) } + function Bar(a : Result, b : Result) : Bool { a == b } + Bar(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 check_rca_for_call_to_function_that_receives_tuple_with_a_non_tuple_dynamic_argument() { + let mut compilation_context = CompilationContext::default(); + compilation_context.update( + r#" + operation Foo() : (Result, Result) { + use q = Qubit(); + (MResetZ(q), Zero) + } + function Bar(a : Result, b : Result) : Bool { a == b } + Bar(Foo())"#, + ); + let package_store_compute_properties = compilation_context.get_compute_properties(); + check_last_statement_compute_properties( + package_store_compute_properties, + &expect![[r#" + ApplicationsGeneratorSet: + inherent: Quantum: QuantumProperties: + runtime_features: RuntimeFeatureFlags(UseOfDynamicBool) + value_kind: Element(Dynamic) + dynamic_param_applications: "#]], + ); +}