diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs index 9c2a732aaf..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( - 140, - ), - }, - 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( - 140, - ), - }, - caller: PackageId( - 2, - ), - functor: FunctorApp { - adjoint: false, - controlled: 1, - }, + QubitUniqueness( + PackageSpan { + package: PackageId( + 2, + ), + span: Span { + lo: 86, + hi: 99, }, - ], + }, ) "#]], ); 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: "#]], + ); +} 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..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 @@ -205,7 +203,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 +241,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 +393,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})