From 9e7dbee76690e7f829f65aef633628773d50e142 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Wed, 22 May 2024 23:36:52 -0700 Subject: [PATCH] Run RCA on interpreter creation and propagate errors (#1560) --- compiler/qsc/src/interpret.rs | 23 ++++++++++++++++++- compiler/qsc/src/interpret/tests.rs | 34 +++++++++++++++++++++++++++++ npm/qsharp/test/basics.js | 20 +++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/compiler/qsc/src/interpret.rs b/compiler/qsc/src/interpret.rs index 17e456d2a1..b59e0b655a 100644 --- a/compiler/qsc/src/interpret.rs +++ b/compiler/qsc/src/interpret.rs @@ -205,6 +205,27 @@ impl Interpreter { let source_package_id = compiler.source_package_id(); let package_id = compiler.package_id(); + + let package = map_hir_package_to_fir(package_id); + if capabilities != TargetCapabilityFlags::all() { + let _ = PassContext::run_fir_passes_on_fir( + &fir_store, + map_hir_package_to_fir(source_package_id), + capabilities, + ) + .map_err(|caps_errors| { + let source_package = compiler + .package_store() + .get(source_package_id) + .expect("package should exist in the package store"); + + caps_errors + .into_iter() + .map(|error| Error::Pass(WithSource::from_map(&source_package.sources, error))) + .collect::>() + })?; + } + Ok(Self { compiler, lines: 0, @@ -215,7 +236,7 @@ impl Interpreter { sim: sim_circuit_backend(), quantum_seed: None, classical_seed: None, - package: map_hir_package_to_fir(package_id), + package, source_package: map_hir_package_to_fir(source_package_id), }) } diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs index 6956438dd5..2e07605d12 100644 --- a/compiler/qsc/src/interpret/tests.rs +++ b/compiler/qsc/src/interpret/tests.rs @@ -1458,6 +1458,40 @@ mod given_interpreter { is_unit_with_output_eval_entry(&result, &output, "hello there..."); } + #[test] + fn errors_returned_if_sources_do_not_match_profile() { + let source = indoc! { r#" + namespace A { operation Test() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x } }"#}; + + let sources = SourceMap::new([("test".into(), source.into())], Some("A.Test()".into())); + let result = Interpreter::new( + true, + sources, + PackageType::Exe, + TargetCapabilityFlags::Adaptive + | TargetCapabilityFlags::IntegerComputations + | TargetCapabilityFlags::QubitReset, + LanguageFeatures::default(), + ); + + match result { + Ok(_) => panic!("Expected error, got interpreter."), + Err(errors) => is_error( + &errors, + &expect![[r#" + cannot use a dynamic double value + [] [A.Test()] + cannot use a double value as an output + [] [A.Test()] + cannot use a dynamic double value + [test] [set x = 2.0] + cannot use a dynamic double value + [test] [x] + "#]], + ), + } + } + #[test] fn stdlib_members_can_be_accessed_from_sources() { let source = indoc! { r#" diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index e84782d97c..2d4c96188b 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -786,6 +786,26 @@ test("debug service loading source with bad entry expr fails - web worker", asyn } }); +test("debug service loading source that doesn't match profile fails - web worker", async () => { + const debugService = getDebugServiceWorker(); + try { + const result = await debugService.loadSource( + [ + [ + "test.qs", + `namespace A { operation Test() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x } }`, + ], + ], + "adaptive_ri", + "A.Test()", + [], + ); + assert.ok(typeof result === "string" && result.trim().length > 0); + } finally { + debugService.terminate(); + } +}); + test("debug service loading source with good entry expr succeeds - web worker", async () => { const debugService = getDebugServiceWorker(); try {