microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/pythontelem

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc/src/interpret/tests.rs

1890lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![allow(clippy::needless_raw_string_hashes)]
5
6mod given_interpreter {
7 use crate::interpret::{InterpretResult, Interpreter};
8 use expect_test::Expect;
9 use miette::Diagnostic;
10 use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
11 use qsc_eval::{output::CursorReceiver, val::Value};
12 use qsc_frontend::compile::SourceMap;
13 use qsc_passes::PackageType;
14 use std::{fmt::Write, io::Cursor, iter, str::from_utf8};
15
16 fn line(interpreter: &mut Interpreter, line: &str) -> (InterpretResult, String) {
17 let mut cursor = Cursor::new(Vec::<u8>::new());
18 let mut receiver = CursorReceiver::new(&mut cursor);
19 (
20 interpreter.eval_fragments(&mut receiver, line),
21 receiver.dump(),
22 )
23 }
24
25 fn run(interpreter: &mut Interpreter, expr: &str) -> (InterpretResult, String) {
26 let mut cursor = Cursor::new(Vec::<u8>::new());
27 let mut receiver = CursorReceiver::new(&mut cursor);
28 (interpreter.run(&mut receiver, Some(expr)), receiver.dump())
29 }
30
31 fn entry(interpreter: &mut Interpreter) -> (InterpretResult, String) {
32 let mut cursor = Cursor::new(Vec::<u8>::new());
33 let mut receiver = CursorReceiver::new(&mut cursor);
34 (interpreter.eval_entry(&mut receiver), receiver.dump())
35 }
36
37 fn fragment(
38 interpreter: &mut Interpreter,
39 fragments: &str,
40 package: crate::ast::Package,
41 ) -> (InterpretResult, String) {
42 let mut cursor = Cursor::new(Vec::<u8>::new());
43 let mut receiver = CursorReceiver::new(&mut cursor);
44 let result = interpreter.eval_ast_fragments(&mut receiver, fragments, package);
45 (result, receiver.dump())
46 }
47
48 mod without_sources {
49 use expect_test::expect;
50 use indoc::indoc;
51
52 use super::*;
53
54 mod without_stdlib {
55 use qsc_frontend::compile::SourceMap;
56 use qsc_passes::PackageType;
57
58 use super::*;
59
60 #[test]
61 fn stdlib_members_should_be_unavailable() {
62 let store = crate::PackageStore::new(crate::compile::core());
63 let mut interpreter = Interpreter::new(
64 SourceMap::default(),
65 PackageType::Lib,
66 TargetCapabilityFlags::all(),
67 LanguageFeatures::default(),
68 store,
69 &[],
70 )
71 .expect("interpreter should be created");
72
73 let (result, output) = line(&mut interpreter, "Message(\"_\")");
74 is_only_error(
75 &result,
76 &output,
77 &expect![[r#"
78 name error: `Message` not found
79 [line_0] [Message]
80 type error: insufficient type information to infer type
81 [line_0] [Message("_")]
82 "#]],
83 );
84 }
85 }
86
87 #[test]
88 fn stdlib_members_should_be_available() {
89 let mut interpreter = get_interpreter();
90 let (result, output) = line(&mut interpreter, "Message(\"_\")");
91 is_unit_with_output(&result, &output, "_");
92 }
93
94 #[test]
95 fn core_members_should_be_available() {
96 let mut interpreter = get_interpreter();
97 let (result, output) = line(&mut interpreter, "Length([1, 2, 3])");
98 is_only_value(&result, &output, &Value::Int(3));
99 }
100
101 #[test]
102 fn let_bindings_update_interpreter() {
103 let mut interpreter = get_interpreter();
104 line(&mut interpreter, "let y = 7;")
105 .0
106 .expect("line should succeed");
107 let (result, output) = line(&mut interpreter, "y");
108 is_only_value(&result, &output, &Value::Int(7));
109 }
110
111 #[test]
112 fn let_bindings_can_be_shadowed() {
113 let mut interpreter = get_interpreter();
114
115 let (result, output) = line(&mut interpreter, "let y = 7;");
116 is_only_value(&result, &output, &Value::unit());
117
118 let (result, output) = line(&mut interpreter, "y");
119 is_only_value(&result, &output, &Value::Int(7));
120
121 let (result, output) = line(&mut interpreter, "let y = \"Hello\";");
122 is_only_value(&result, &output, &Value::unit());
123
124 let (result, output) = line(&mut interpreter, "y");
125 is_only_value(&result, &output, &Value::String("Hello".into()));
126 }
127
128 #[test]
129 fn invalid_statements_return_error() {
130 let mut interpreter = get_interpreter();
131
132 let (result, output) = line(&mut interpreter, "let y = 7");
133 is_only_error(
134 &result,
135 &output,
136 &expect![[r#"
137 syntax error: expected `;`, found EOF
138 [line_0] []
139 "#]],
140 );
141
142 let (result, output) = line(&mut interpreter, "y");
143 is_only_error(
144 &result,
145 &output,
146 &expect![[r#"
147 name error: `y` not found
148 [line_1] [y]
149 "#]],
150 );
151 }
152
153 #[test]
154 fn invalid_statements_and_unbound_vars_return_error() {
155 let mut interpreter = get_interpreter();
156
157 let (result, output) = line(&mut interpreter, "let y = x;");
158 is_only_error(
159 &result,
160 &output,
161 &expect![[r#"
162 name error: `x` not found
163 [line_0] [x]
164 type error: insufficient type information to infer type
165 [line_0] [y]
166 "#]],
167 );
168
169 let (result, output) = line(&mut interpreter, "y");
170 is_only_error(
171 &result,
172 &output,
173 &expect![[r#"
174 runtime error: name is not bound
175 [line_1] [y]
176 "#]],
177 );
178 }
179
180 #[test]
181 fn failing_statements_return_early_error() {
182 let mut interpreter = get_interpreter();
183 let (result, output) = line(&mut interpreter, "let y = 7;y/0;y");
184 is_only_error(
185 &result,
186 &output,
187 &expect![[r#"
188 runtime error: division by zero
189 cannot divide by zero [line_0] [0]
190 "#]],
191 );
192 }
193
194 #[test]
195 fn passes_are_run_on_incremental() {
196 let mut interpreter = get_interpreter();
197 let (result, output) = line(
198 &mut interpreter,
199 "within {Message(\"A\");} apply {Message(\"B\");}",
200 );
201 is_unit_with_output(&result, &output, "A\nB\nA");
202 }
203
204 #[test]
205 fn declare_function() {
206 let mut interpreter = get_interpreter();
207 let (result, output) = line(&mut interpreter, "function Foo() : Int { 2 }");
208 is_only_value(&result, &output, &Value::unit());
209 let (result, output) = line(&mut interpreter, "Foo()");
210 is_only_value(&result, &output, &Value::Int(2));
211 }
212
213 #[test]
214 fn invalid_declare_function_and_unbound_call_return_error() {
215 let mut interpreter = get_interpreter();
216 let (result, output) = line(&mut interpreter, "function Foo() : Int { invalid }");
217 is_only_error(
218 &result,
219 &output,
220 &expect![[r#"
221 name error: `invalid` not found
222 [line_0] [invalid]
223 "#]],
224 );
225 let (result, output) = line(&mut interpreter, "Foo()");
226 is_only_error(
227 &result,
228 &output,
229 &expect![[r#"
230 runtime error: name is not bound
231 [line_1] [Foo]
232 "#]],
233 );
234 }
235
236 #[test]
237 fn declare_function_call_same_line() {
238 let mut interpreter = get_interpreter();
239 let (result, output) = line(&mut interpreter, "function Foo() : Int { 2 }; Foo()");
240 is_only_value(&result, &output, &Value::Int(2));
241 }
242
243 #[test]
244 fn let_binding_function_declaration_call_same_line() {
245 let mut interpreter = get_interpreter();
246 let (result, output) = line(
247 &mut interpreter,
248 "let x = 1; function Foo() : Int { 2 }; Foo() + 1",
249 );
250 is_only_value(&result, &output, &Value::Int(3));
251 }
252
253 #[test]
254 fn nested_function() {
255 let mut interpreter = get_interpreter();
256 let (result, output) = line(
257 &mut interpreter,
258 "function Foo() : Int { function Bar() : Int { 1 }; Bar() + 1 }; Foo() + 1",
259 );
260 is_only_value(&result, &output, &Value::Int(3));
261 }
262
263 #[test]
264 fn open_namespace() {
265 let mut interpreter = get_interpreter();
266 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
267 is_only_value(&result, &output, &Value::unit());
268 let (result, output) = line(&mut interpreter, "DumpMachine()");
269 is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i");
270 }
271
272 #[test]
273 fn open_namespace_call_same_line() {
274 let mut interpreter = get_interpreter();
275 let (result, output) = line(
276 &mut interpreter,
277 "open Microsoft.Quantum.Diagnostics; DumpMachine()",
278 );
279 is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i");
280 }
281
282 #[test]
283 fn declare_namespace_call() {
284 let mut interpreter = get_interpreter();
285 let (result, output) = line(
286 &mut interpreter,
287 "namespace Foo { function Bar() : Int { 5 } }",
288 );
289 is_only_value(&result, &output, &Value::unit());
290 let (result, output) = line(&mut interpreter, "Foo.Bar()");
291 is_only_value(&result, &output, &Value::Int(5));
292 }
293
294 #[test]
295 fn declare_namespace_open_call() {
296 let mut interpreter = get_interpreter();
297 let (result, output) = line(
298 &mut interpreter,
299 "namespace Foo { function Bar() : Int { 5 } }",
300 );
301 is_only_value(&result, &output, &Value::unit());
302 let (result, output) = line(&mut interpreter, "open Foo;");
303 is_only_value(&result, &output, &Value::unit());
304 let (result, output) = line(&mut interpreter, "Bar()");
305 is_only_value(&result, &output, &Value::Int(5));
306 }
307
308 #[test]
309 fn declare_namespace_open_call_same_line() {
310 let mut interpreter = get_interpreter();
311 let (result, output) = line(
312 &mut interpreter,
313 "namespace Foo { function Bar() : Int { 5 } } open Foo; Bar()",
314 );
315 is_only_value(&result, &output, &Value::Int(5));
316 }
317
318 #[test]
319 fn mix_stmts_and_namespace_same_line() {
320 let mut interpreter = get_interpreter();
321 let (result, output) = line(
322 &mut interpreter,
323 "Message(\"before\"); namespace Foo { function Bar() : Int { 5 } } Message(\"after\")",
324 );
325 is_unit_with_output(&result, &output, "before\nafter");
326 }
327
328 #[test]
329 fn global_qubits() {
330 let mut interpreter = get_interpreter();
331 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
332 is_only_value(&result, &output, &Value::unit());
333 let (result, output) = line(&mut interpreter, "DumpMachine()");
334 is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i");
335 let (result, output) = line(&mut interpreter, "use (q0, qs) = (Qubit(), Qubit[3]);");
336 is_only_value(&result, &output, &Value::unit());
337 let (result, output) = line(&mut interpreter, "DumpMachine()");
338 is_unit_with_output(&result, &output, "STATE:\n|0000⟩: 1+0i");
339 let (result, output) = line(&mut interpreter, "X(q0); X(qs[1]);");
340 is_only_value(&result, &output, &Value::unit());
341 let (result, output) = line(&mut interpreter, "DumpMachine()");
342 is_unit_with_output(&result, &output, "STATE:\n|1010⟩: 1+0i");
343 }
344
345 #[test]
346 fn ambiguous_type_error_in_top_level_stmts() {
347 let mut interpreter = get_interpreter();
348 let (result, output) = line(&mut interpreter, "let x = [];");
349 is_only_error(
350 &result,
351 &output,
352 &expect![[r#"
353 type error: insufficient type information to infer type
354 [line_0] [[]]
355 "#]],
356 );
357 let (result, output) = line(&mut interpreter, "let x = []; let y = [0] + x;");
358 is_only_value(&result, &output, &Value::unit());
359 let (result, output) = line(&mut interpreter, "function Foo() : Unit { let x = []; }");
360 is_only_error(
361 &result,
362 &output,
363 &expect![[r#"
364 type error: insufficient type information to infer type
365 [line_2] [[]]
366 "#]],
367 );
368 }
369
370 #[test]
371 fn resolved_type_persists_across_stmts() {
372 let mut interpreter = get_interpreter();
373 let (result, output) = line(&mut interpreter, "let x = []; let y = [0] + x;");
374 is_only_value(&result, &output, &Value::unit());
375 let (result, output) = line(&mut interpreter, "let z = [0.0] + x;");
376 is_only_error(
377 &result,
378 &output,
379 &expect![[r#"
380 type error: expected Double, found Int
381 [line_1] [x]
382 "#]],
383 );
384 }
385
386 #[test]
387 fn incremental_lambas_work() {
388 let mut interpreter = get_interpreter();
389 let (result, output) = line(&mut interpreter, "let x = 1; let f = (y) -> x + y;");
390 is_only_value(&result, &output, &Value::unit());
391 let (result, output) = line(&mut interpreter, "f(1)");
392 is_only_value(&result, &output, &Value::Int(2));
393 }
394
395 #[test]
396 fn mutability_persists_across_stmts() {
397 let mut interpreter = get_interpreter();
398 let (result, output) = line(
399 &mut interpreter,
400 "mutable x : Int[] = []; let y : Int[] = [];",
401 );
402 is_only_value(&result, &output, &Value::unit());
403 let (result, output) = line(&mut interpreter, "set x += [0];");
404 is_only_value(&result, &output, &Value::unit());
405 let (result, output) = line(&mut interpreter, "set y += [0];");
406 is_only_error(
407 &result,
408 &output,
409 &expect![[r#"
410 cannot update immutable variable
411 [line_2] [y]
412 "#]],
413 );
414 let (result, output) = line(&mut interpreter, "let lam = () -> y + [0];");
415 is_only_value(&result, &output, &Value::unit());
416 let (result, output) = line(&mut interpreter, "let lam = () -> x + [0];");
417 is_only_error(
418 &result,
419 &output,
420 &expect![[r#"
421 lambdas cannot close over mutable variables
422 [line_4] [() -> x + [0]]
423 "#]],
424 );
425 }
426
427 #[test]
428 fn runtime_error_across_lines() {
429 let mut interpreter = get_interpreter();
430 let (result, output) = line(
431 &mut interpreter,
432 "operation Main() : Unit { Microsoft.Quantum.Random.DrawRandomInt(2,1); }",
433 );
434 is_only_value(&result, &output, &Value::unit());
435 let (result, output) = line(&mut interpreter, "Main()");
436 is_only_error(
437 &result,
438 &output,
439 &expect![[r#"
440 runtime error: empty range
441 the range cannot be empty [line_0] [(2,1)]
442 "#]],
443 );
444 }
445
446 #[test]
447 fn compiler_error_across_lines() {
448 let mut interpreter = get_interpreter();
449 let (result, output) = line(
450 &mut interpreter,
451 "namespace Other { operation DumpMachine() : Unit { } }",
452 );
453 is_only_value(&result, &output, &Value::unit());
454 let (result, output) = line(&mut interpreter, "open Other;");
455 is_only_value(&result, &output, &Value::unit());
456 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
457 is_only_value(&result, &output, &Value::unit());
458 let (result, output) = line(&mut interpreter, "DumpMachine();");
459 is_only_error(
460 &result,
461 &output,
462 &expect![[r#"
463 name error: `DumpMachine` could refer to the item in `Other` or `Microsoft.Quantum.Diagnostics`
464 ambiguous name [line_3] [DumpMachine]
465 found in this namespace [line_1] [Other]
466 and also in this namespace [line_2] [Std.Diagnostics]
467 type error: insufficient type information to infer type
468 [line_3] [DumpMachine()]
469 "#]],
470 );
471 }
472
473 #[test]
474 fn runtime_error_from_stdlib() {
475 let mut interpreter = get_interpreter();
476 let (result, output) = line(&mut interpreter, "use q = Qubit(); CNOT(q,q)");
477 is_only_error(
478 &result,
479 &output,
480 &expect![[r#"
481 runtime error: qubits in invocation are not unique
482 [qsharp-library-source:Std/Intrinsic.qs] [(control, target)]
483 "#]],
484 );
485 }
486
487 #[test]
488 fn items_usable_before_definition() {
489 let mut interpreter = get_interpreter();
490 let (result, output) = line(
491 &mut interpreter,
492 indoc! {r#"
493 function A() : Unit {
494 B();
495 }
496 function B() : Unit {}
497 A()
498 "#},
499 );
500 is_only_value(&result, &output, &Value::unit());
501 }
502
503 #[test]
504 fn items_usable_before_definition_top_level() {
505 let mut interpreter = get_interpreter();
506 let (result, output) = line(
507 &mut interpreter,
508 indoc! {r#"
509 B();
510 function B() : Unit {}
511 "#},
512 );
513 is_only_value(&result, &output, &Value::unit());
514 }
515
516 #[test]
517 fn callables_failing_profile_validation_are_not_registered() {
518 let mut interpreter =
519 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
520 let (result, output) = line(
521 &mut interpreter,
522 indoc! {r#"
523 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
524 "#},
525 );
526 is_only_error(
527 &result,
528 &output,
529 &expect![[r#"
530 cannot use a dynamic integer value
531 [line_0] [set x = 2]
532 cannot use a dynamic integer value
533 [line_0] [x]
534 "#]],
535 );
536 // do something innocuous
537 let (result, output) = line(&mut interpreter, indoc! {r#"Foo()"#});
538 // since the callable wasn't registered, this will return an unbound name error.
539 is_only_error(
540 &result,
541 &output,
542 &expect![[r#"
543 runtime error: name is not bound
544 [line_1] [Foo]
545 "#]],
546 );
547 }
548
549 #[test]
550 fn callables_failing_profile_validation_also_fail_qir_generation() {
551 let mut interpreter =
552 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
553 let (result, output) = line(
554 &mut interpreter,
555 indoc! {r#"
556 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
557 "#},
558 );
559 is_only_error(
560 &result,
561 &output,
562 &expect![[r#"
563 cannot use a dynamic integer value
564 [line_0] [set x = 2]
565 cannot use a dynamic integer value
566 [line_0] [x]
567 "#]],
568 );
569 let res = interpreter.qirgen("{Foo();}");
570 expect![[r#"
571 Err(
572 [
573 PartialEvaluation(
574 WithSource {
575 sources: [
576 Source {
577 name: "<entry>",
578 contents: "{Foo();}",
579 offset: 97,
580 },
581 ],
582 error: EvaluationFailed(
583 "name is not bound",
584 PackageSpan {
585 package: PackageId(
586 3,
587 ),
588 span: Span {
589 lo: 98,
590 hi: 101,
591 },
592 },
593 ),
594 },
595 ),
596 ],
597 )
598 "#]]
599 .assert_debug_eq(&res);
600 }
601
602 #[test]
603 fn once_rca_validation_fails_following_calls_do_not_fail() {
604 let mut interpreter =
605 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
606 let (result, output) = line(
607 &mut interpreter,
608 indoc! {r#"
609 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
610 "#},
611 );
612 is_only_error(
613 &result,
614 &output,
615 &expect![[r#"
616 cannot use a dynamic integer value
617 [line_0] [set x = 2]
618 cannot use a dynamic integer value
619 [line_0] [x]
620 "#]],
621 );
622 // do something innocuous
623 let (result, output) = line(
624 &mut interpreter,
625 indoc! {r#"
626 let y = 7;
627 "#},
628 );
629 is_only_value(&result, &output, &Value::unit());
630 }
631
632 #[test]
633 fn namespace_usable_before_definition() {
634 let mut interpreter = get_interpreter();
635 let (result, output) = line(
636 &mut interpreter,
637 indoc! {r#"
638 A.B();
639 namespace A {
640 function B() : Unit {}
641 }
642 "#},
643 );
644 is_only_value(&result, &output, &Value::unit());
645 }
646
647 #[test]
648 fn mutually_recursive_namespaces_work() {
649 let mut interpreter = get_interpreter();
650 let (result, output) = line(
651 &mut interpreter,
652 indoc! {r#"
653 A.B();
654 namespace A {
655 open C;
656 function B() : Unit {
657 D();
658 }
659 function E() : Unit {}
660 }
661 namespace C {
662 open A;
663 function D() : Unit {
664 E();
665 }
666 }
667 "#},
668 );
669 is_only_value(&result, &output, &Value::unit());
670 }
671
672 #[test]
673 fn local_var_valid_after_item_definition() {
674 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
675 let (result, output) = line(&mut interpreter, "let a = 1;");
676 is_only_value(&result, &output, &Value::unit());
677 let (result, output) = line(&mut interpreter, "a");
678 is_only_value(&result, &output, &Value::Int(1));
679 let (result, output) = line(
680 &mut interpreter,
681 "function B() : Int { let inner_b = 3; inner_b }",
682 );
683 is_only_value(&result, &output, &Value::unit());
684 let (result, output) = line(&mut interpreter, "B()");
685 is_only_value(&result, &output, &Value::Int(3));
686 let (result, output) = line(&mut interpreter, "let b = 2;");
687 is_only_value(&result, &output, &Value::unit());
688 let (result, output) = line(&mut interpreter, "b");
689 is_only_value(&result, &output, &Value::Int(2));
690 let (result, output) = line(&mut interpreter, "a");
691 is_only_value(&result, &output, &Value::Int(1));
692 let (result, output) = line(&mut interpreter, "B()");
693 is_only_value(&result, &output, &Value::Int(3));
694 }
695
696 #[test]
697 fn base_qirgen() {
698 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
699 let (result, output) = line(
700 &mut interpreter,
701 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
702 );
703 is_only_value(&result, &output, &Value::unit());
704 let res = interpreter.qirgen("Foo()").expect("expected success");
705 expect![[r#"
706 %Result = type opaque
707 %Qubit = type opaque
708
709 define void @ENTRYPOINT__main() #0 {
710 block_0:
711 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
712 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
713 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
714 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
715 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
716 ret void
717 }
718
719 declare void @__quantum__qis__h__body(%Qubit*)
720
721 declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
722
723 declare void @__quantum__rt__result_record_output(%Result*, i8*)
724
725 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
726
727 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
728 attributes #1 = { "irreversible" }
729
730 ; module flags
731
732 !llvm.module.flags = !{!0, !1, !2, !3}
733
734 !0 = !{i32 1, !"qir_major_version", i32 1}
735 !1 = !{i32 7, !"qir_minor_version", i32 0}
736 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
737 !3 = !{i32 1, !"dynamic_result_management", i1 false}
738 "#]].assert_eq(&res);
739 }
740
741 #[test]
742 fn adaptive_qirgen() {
743 let mut interpreter = get_interpreter_with_capabilities(
744 TargetCapabilityFlags::Adaptive
745 | TargetCapabilityFlags::QubitReset
746 | TargetCapabilityFlags::IntegerComputations,
747 );
748 let (result, output) = line(
749 &mut interpreter,
750 indoc! {r#"
751 namespace Test {
752 import Std.Math.*;
753 open QIR.Intrinsic;
754 @EntryPoint()
755 operation Main() : Result {
756 use q = Qubit();
757 let pi_over_2 = 4.0 / 2.0;
758 __quantum__qis__rz__body(pi_over_2, q);
759 mutable some_angle = ArcSin(0.0);
760 __quantum__qis__rz__body(some_angle, q);
761 set some_angle = ArcCos(-1.0) / PI();
762 __quantum__qis__rz__body(some_angle, q);
763 __quantum__qis__mresetz__body(q)
764 }
765 }"#
766 },
767 );
768 is_only_value(&result, &output, &Value::unit());
769 let res = interpreter.qirgen("Test.Main()").expect("expected success");
770 expect![[r#"
771 %Result = type opaque
772 %Qubit = type opaque
773
774 define void @ENTRYPOINT__main() #0 {
775 block_0:
776 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
777 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
778 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
779 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
780 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
781 ret void
782 }
783
784 declare void @__quantum__qis__rz__body(double, %Qubit*)
785
786 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
787
788 declare void @__quantum__rt__result_record_output(%Result*, i8*)
789
790 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
791 attributes #1 = { "irreversible" }
792
793 ; module flags
794
795 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
796
797 !0 = !{i32 1, !"qir_major_version", i32 1}
798 !1 = !{i32 7, !"qir_minor_version", i32 0}
799 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
800 !3 = !{i32 1, !"dynamic_result_management", i1 false}
801 !4 = !{i32 1, !"classical_ints", i1 true}
802 !5 = !{i32 1, !"qubit_resetting", i1 true}
803 !6 = !{i32 1, !"classical_floats", i1 false}
804 !7 = !{i32 1, !"backwards_branching", i1 false}
805 !8 = !{i32 1, !"classical_fixed_points", i1 false}
806 !9 = !{i32 1, !"user_functions", i1 false}
807 !10 = !{i32 1, !"multiple_target_branching", i1 false}
808 "#]]
809 .assert_eq(&res);
810 }
811
812 #[test]
813 fn adaptive_qirgen_nested_output_types() {
814 let mut interpreter = get_interpreter_with_capabilities(
815 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::QubitReset,
816 );
817 let (result, output) = line(
818 &mut interpreter,
819 indoc! {r#"
820 namespace Test {
821 open QIR.Intrinsic;
822 @EntryPoint()
823 operation Main() : (Result, (Bool, Bool)) {
824 use q = Qubit();
825 let r = __quantum__qis__mresetz__body(q);
826 (r, (r == One, r == Zero))
827 }
828 }"#
829 },
830 );
831 is_only_value(&result, &output, &Value::unit());
832 let res = interpreter.qirgen("Test.Main()").expect("expected success");
833 expect![[r#"
834 %Result = type opaque
835 %Qubit = type opaque
836
837 define void @ENTRYPOINT__main() #0 {
838 block_0:
839 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
840 %var_0 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
841 %var_2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 0 to %Result*))
842 %var_3 = icmp eq i1 %var_2, false
843 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
844 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
845 call void @__quantum__rt__tuple_record_output(i64 2, i8* null)
846 call void @__quantum__rt__bool_record_output(i1 %var_0, i8* null)
847 call void @__quantum__rt__bool_record_output(i1 %var_3, i8* null)
848 ret void
849 }
850
851 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
852
853 declare i1 @__quantum__qis__read_result__body(%Result*)
854
855 declare void @__quantum__rt__tuple_record_output(i64, i8*)
856
857 declare void @__quantum__rt__result_record_output(%Result*, i8*)
858
859 declare void @__quantum__rt__bool_record_output(i1, i8*)
860
861 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
862 attributes #1 = { "irreversible" }
863
864 ; module flags
865
866 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
867
868 !0 = !{i32 1, !"qir_major_version", i32 1}
869 !1 = !{i32 7, !"qir_minor_version", i32 0}
870 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
871 !3 = !{i32 1, !"dynamic_result_management", i1 false}
872 !4 = !{i32 1, !"qubit_resetting", i1 true}
873 !5 = !{i32 1, !"classical_ints", i1 false}
874 !6 = !{i32 1, !"classical_floats", i1 false}
875 !7 = !{i32 1, !"backwards_branching", i1 false}
876 !8 = !{i32 1, !"classical_fixed_points", i1 false}
877 !9 = !{i32 1, !"user_functions", i1 false}
878 !10 = !{i32 1, !"multiple_target_branching", i1 false}
879 "#]]
880 .assert_eq(&res);
881 }
882
883 #[test]
884 fn adaptive_qirgen_fails_when_entry_expr_does_not_match_profile() {
885 let mut interpreter =
886 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
887 let (result, output) = line(
888 &mut interpreter,
889 indoc! {r#"
890 use q = Qubit();
891 mutable x = 1;
892 "#
893 },
894 );
895 is_only_value(&result, &output, &Value::unit());
896 let res = interpreter
897 .qirgen("if M(q) == One { set x = 2; }")
898 .expect_err("expected error");
899 is_error(
900 &res,
901 &expect![[r#"
902 cannot use a dynamic integer value
903 [<entry>] [set x = 2]
904 "#]],
905 );
906 }
907
908 #[test]
909 fn qirgen_entry_expr_in_block() {
910 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
911 let (result, output) = line(
912 &mut interpreter,
913 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
914 );
915 is_only_value(&result, &output, &Value::unit());
916 let res = interpreter.qirgen("{Foo()}").expect("expected success");
917 expect![[r#"
918 %Result = type opaque
919 %Qubit = type opaque
920
921 define void @ENTRYPOINT__main() #0 {
922 block_0:
923 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
924 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
925 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
926 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
927 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
928 ret void
929 }
930
931 declare void @__quantum__qis__h__body(%Qubit*)
932
933 declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
934
935 declare void @__quantum__rt__result_record_output(%Result*, i8*)
936
937 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
938
939 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
940 attributes #1 = { "irreversible" }
941
942 ; module flags
943
944 !llvm.module.flags = !{!0, !1, !2, !3}
945
946 !0 = !{i32 1, !"qir_major_version", i32 1}
947 !1 = !{i32 7, !"qir_minor_version", i32 0}
948 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
949 !3 = !{i32 1, !"dynamic_result_management", i1 false}
950 "#]].assert_eq(&res);
951 }
952
953 #[test]
954 fn qirgen_entry_expr_defines_operation() {
955 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
956
957 let (result, output) = line(
958 &mut interpreter,
959 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
960 );
961 is_only_value(&result, &output, &Value::unit());
962 let res = interpreter
963 .qirgen("{operation Bar() : Unit {}; Foo()}")
964 .expect("expected success");
965 expect![[r#"
966 %Result = type opaque
967 %Qubit = type opaque
968
969 define void @ENTRYPOINT__main() #0 {
970 block_0:
971 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
972 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
973 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
974 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
975 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
976 ret void
977 }
978
979 declare void @__quantum__qis__h__body(%Qubit*)
980
981 declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
982
983 declare void @__quantum__rt__result_record_output(%Result*, i8*)
984
985 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
986
987 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
988 attributes #1 = { "irreversible" }
989
990 ; module flags
991
992 !llvm.module.flags = !{!0, !1, !2, !3}
993
994 !0 = !{i32 1, !"qir_major_version", i32 1}
995 !1 = !{i32 7, !"qir_minor_version", i32 0}
996 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
997 !3 = !{i32 1, !"dynamic_result_management", i1 false}
998 "#]].assert_eq(&res);
999
1000 // Operation should not be visible from global scope
1001 let (result, output) = line(&mut interpreter, indoc! {"Bar()"});
1002 is_only_error(
1003 &result,
1004 &output,
1005 &expect![[r#"
1006 name error: `Bar` not found
1007 [line_1] [Bar]
1008 type error: insufficient type information to infer type
1009 [line_1] [Bar()]
1010 "#]],
1011 );
1012 }
1013
1014 #[test]
1015 fn qirgen_multiple_exprs_parse_fail() {
1016 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1017 let (result, output) = line(
1018 &mut interpreter,
1019 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1020 );
1021 is_only_value(&result, &output, &Value::unit());
1022 let res = interpreter
1023 .qirgen("Foo(); operation Bar() : Unit {}; Foo()")
1024 .expect_err("expected error");
1025 is_error(
1026 &res,
1027 &expect![[r#"
1028 syntax error: expected EOF, found `;`
1029 [<entry>] [;]
1030 "#]],
1031 );
1032 }
1033
1034 #[test]
1035 fn qirgen_entry_expr_defines_operation_then_more_operations() {
1036 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1037 let (result, output) = line(
1038 &mut interpreter,
1039 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1040 );
1041 is_only_value(&result, &output, &Value::unit());
1042 let res = interpreter
1043 .qirgen("{operation Bar() : Unit {}; Foo()}")
1044 .expect("expected success");
1045 expect![[r#"
1046 %Result = type opaque
1047 %Qubit = type opaque
1048
1049 define void @ENTRYPOINT__main() #0 {
1050 block_0:
1051 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1052 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1053 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1054 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1055 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
1056 ret void
1057 }
1058
1059 declare void @__quantum__qis__h__body(%Qubit*)
1060
1061 declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1062
1063 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1064
1065 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1066
1067 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1068 attributes #1 = { "irreversible" }
1069
1070 ; module flags
1071
1072 !llvm.module.flags = !{!0, !1, !2, !3}
1073
1074 !0 = !{i32 1, !"qir_major_version", i32 1}
1075 !1 = !{i32 7, !"qir_minor_version", i32 0}
1076 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1077 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1078 "#]].assert_eq(&res);
1079
1080 let (result, output) = line(
1081 &mut interpreter,
1082 indoc! {"operation Baz() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1083 );
1084 is_only_value(&result, &output, &Value::unit());
1085
1086 let (result, output) = line(&mut interpreter, indoc! {"Bar()"});
1087 is_only_error(
1088 &result,
1089 &output,
1090 &expect![[r#"
1091 name error: `Bar` not found
1092 [line_2] [Bar]
1093 type error: insufficient type information to infer type
1094 [line_2] [Bar()]
1095 "#]],
1096 );
1097 }
1098
1099 #[test]
1100 fn qirgen_define_operation_use_it() {
1101 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1102 let res = interpreter
1103 .qirgen("{ operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; }; Foo() }")
1104 .expect("expected success");
1105 expect![[r#"
1106 %Result = type opaque
1107 %Qubit = type opaque
1108
1109 define void @ENTRYPOINT__main() #0 {
1110 block_0:
1111 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1112 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1113 call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1114 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1115 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
1116 ret void
1117 }
1118
1119 declare void @__quantum__qis__h__body(%Qubit*)
1120
1121 declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1122
1123 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1124
1125 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1126
1127 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1128 attributes #1 = { "irreversible" }
1129
1130 ; module flags
1131
1132 !llvm.module.flags = !{!0, !1, !2, !3}
1133
1134 !0 = !{i32 1, !"qir_major_version", i32 1}
1135 !1 = !{i32 7, !"qir_minor_version", i32 0}
1136 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1137 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1138 "#]].assert_eq(&res);
1139 }
1140
1141 #[test]
1142 fn qirgen_entry_expr_profile_incompatible() {
1143 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1144 let res = interpreter
1145 .qirgen("1")
1146 .expect_err("expected qirgen to fail");
1147 is_error(
1148 &res,
1149 &expect![[r#"
1150 cannot use an integer value as an output
1151 [<entry>] [1]
1152 "#]],
1153 );
1154 }
1155
1156 #[test]
1157 fn run_with_shots() {
1158 let mut interpreter = get_interpreter();
1159 let (result, output) = line(&mut interpreter, "operation Foo(qs : Qubit[]) : Unit { Microsoft.Quantum.Diagnostics.DumpMachine(); }");
1160 is_only_value(&result, &output, &Value::unit());
1161 for _ in 0..4 {
1162 let (results, output) = run(&mut interpreter, "{use qs = Qubit[2]; Foo(qs)}");
1163 is_unit_with_output(&results, &output, "STATE:\n|00⟩: 1+0i");
1164 }
1165 }
1166
1167 #[test]
1168 fn run_parse_error() {
1169 let mut interpreter = get_interpreter();
1170 let (results, _) = run(&mut interpreter, "Foo)");
1171 results.expect_err("run() should fail");
1172 }
1173
1174 #[test]
1175 fn run_compile_error() {
1176 let mut interpreter = get_interpreter();
1177 let (results, _) = run(&mut interpreter, "Foo()");
1178 results.expect_err("run() should fail");
1179 }
1180
1181 #[test]
1182 fn run_multiple_statements_with_return_value() {
1183 let mut interpreter = get_interpreter();
1184 let (result, output) = line(&mut interpreter, "operation Foo() : Int { 1 }");
1185 is_only_value(&result, &output, &Value::unit());
1186 let (result, output) = line(&mut interpreter, "operation Bar() : Int { 2 }");
1187 is_only_value(&result, &output, &Value::unit());
1188 let (result, output) = run(&mut interpreter, "{ Foo(); Bar() }");
1189 is_only_value(&result, &output, &Value::Int(2));
1190 }
1191
1192 #[test]
1193 fn run_runtime_failure() {
1194 let mut interpreter = get_interpreter();
1195 let (result, output) = line(
1196 &mut interpreter,
1197 r#"operation Foo() : Int { fail "failed" }"#,
1198 );
1199 is_only_value(&result, &output, &Value::unit());
1200 for _ in 0..1 {
1201 let (result, output) = run(&mut interpreter, "Foo()");
1202 is_only_error(
1203 &result,
1204 &output,
1205 &expect![[r#"
1206 runtime error: program failed: failed
1207 explicit fail [line_0] [fail "failed"]
1208 "#]],
1209 );
1210 }
1211 }
1212
1213 #[test]
1214 fn run_output_merged() {
1215 let mut interpreter = get_interpreter();
1216 let (result, output) = line(
1217 &mut interpreter,
1218 r#"operation Foo() : Unit { Message("hello!") }"#,
1219 );
1220 is_only_value(&result, &output, &Value::unit());
1221 for _ in 0..4 {
1222 let (result, output) = run(&mut interpreter, "Foo()");
1223 is_unit_with_output(&result, &output, "hello!");
1224 }
1225 }
1226
1227 #[test]
1228 fn base_prof_non_result_return() {
1229 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1230 let (result, output) = line(&mut interpreter, "123");
1231 is_only_value(&result, &output, &Value::Int(123));
1232 }
1233 }
1234
1235 fn get_interpreter() -> Interpreter {
1236 let (std_id, store) =
1237 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1238 let dependencies = &[(std_id, None)];
1239 Interpreter::new(
1240 SourceMap::default(),
1241 PackageType::Lib,
1242 TargetCapabilityFlags::all(),
1243 LanguageFeatures::default(),
1244 store,
1245 dependencies,
1246 )
1247 .expect("interpreter should be created")
1248 }
1249
1250 fn get_interpreter_with_capabilities(capabilities: TargetCapabilityFlags) -> Interpreter {
1251 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
1252 let dependencies = &[(std_id, None)];
1253 Interpreter::new(
1254 SourceMap::default(),
1255 PackageType::Lib,
1256 capabilities,
1257 LanguageFeatures::default(),
1258 store,
1259 dependencies,
1260 )
1261 .expect("interpreter should be created")
1262 }
1263
1264 fn is_only_value(result: &InterpretResult, output: &str, value: &Value) {
1265 assert_eq!("", output);
1266
1267 match result {
1268 Ok(v) => assert_eq!(value, v),
1269 Err(e) => panic!("Expected {value:?}, got {e:?}"),
1270 }
1271 }
1272
1273 fn is_unit_with_output_eval_entry(
1274 result: &InterpretResult,
1275 output: &str,
1276 expected_output: &str,
1277 ) {
1278 assert_eq!(expected_output, output);
1279
1280 match result {
1281 Ok(value) => assert_eq!(Value::unit(), *value),
1282 Err(e) => panic!("Expected unit value, got {e:?}"),
1283 }
1284 }
1285
1286 fn is_unit_with_output(result: &InterpretResult, output: &str, expected_output: &str) {
1287 assert_eq!(expected_output, output);
1288
1289 match result {
1290 Ok(value) => assert_eq!(Value::unit(), *value),
1291 Err(e) => panic!("Expected unit value, got {e:?}"),
1292 }
1293 }
1294
1295 fn is_only_error<E>(result: &Result<Value, Vec<E>>, output: &str, expected_errors: &Expect)
1296 where
1297 E: Diagnostic,
1298 {
1299 assert_eq!("", output);
1300
1301 match result {
1302 Ok(value) => panic!("Expected error , got {value:?}"),
1303 Err(errors) => is_error(errors, expected_errors),
1304 }
1305 }
1306
1307 fn is_error<E>(errors: &Vec<E>, expected_errors: &Expect)
1308 where
1309 E: Diagnostic,
1310 {
1311 let mut actual = String::new();
1312 for error in errors {
1313 write!(actual, "{error}").expect("writing should succeed");
1314 for s in iter::successors(error.source(), |&s| s.source()) {
1315 write!(actual, ": {s}").expect("writing should succeed");
1316 }
1317 for label in error.labels().into_iter().flatten() {
1318 let span = error
1319 .source_code()
1320 .expect("expected valid source code")
1321 .read_span(label.inner(), 0, 0)
1322 .expect("expected to be able to read span");
1323
1324 write!(
1325 actual,
1326 "\n {} [{}] [{}]",
1327 label.label().unwrap_or(""),
1328 span.name().expect("expected source file name"),
1329 from_utf8(span.data()).expect("expected valid utf-8 string"),
1330 )
1331 .expect("writing should succeed");
1332 }
1333 writeln!(actual).expect("writing should succeed");
1334 }
1335
1336 expected_errors.assert_eq(&actual);
1337 }
1338
1339 #[cfg(test)]
1340 mod with_sources {
1341 use std::{sync::Arc, vec};
1342
1343 use super::*;
1344 use crate::interpret::Debugger;
1345 use crate::line_column::Encoding;
1346 use expect_test::expect;
1347 use indoc::indoc;
1348
1349 use qsc_ast::ast::{
1350 Expr, ExprKind, NodeId, Package, Path, PathKind, Stmt, StmtKind, TopLevelNode,
1351 };
1352 use qsc_data_structures::span::Span;
1353 use qsc_frontend::compile::SourceMap;
1354 use qsc_passes::PackageType;
1355
1356 #[test]
1357 fn entry_expr_is_executed() {
1358 let source = indoc! { r#"
1359 namespace Test {
1360 @EntryPoint()
1361 operation Main() : Unit {
1362 Message("hello there...")
1363 }
1364 }"#};
1365
1366 let sources = SourceMap::new([("test".into(), source.into())], None);
1367 let (std_id, store) =
1368 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1369 let mut interpreter = Interpreter::new(
1370 sources,
1371 PackageType::Exe,
1372 TargetCapabilityFlags::all(),
1373 LanguageFeatures::default(),
1374 store,
1375 &[(std_id, None)],
1376 )
1377 .expect("interpreter should be created");
1378
1379 let (result, output) = entry(&mut interpreter);
1380 is_unit_with_output_eval_entry(&result, &output, "hello there...");
1381 }
1382
1383 #[test]
1384 fn errors_returned_if_sources_do_not_match_profile() {
1385 let source = indoc! { r#"
1386 namespace A { operation Test() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x } }"#};
1387
1388 let sources = SourceMap::new([("test".into(), source.into())], Some("A.Test()".into()));
1389 let (std_id, store) =
1390 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1391 let result = Interpreter::new(
1392 sources,
1393 PackageType::Exe,
1394 TargetCapabilityFlags::Adaptive
1395 | TargetCapabilityFlags::IntegerComputations
1396 | TargetCapabilityFlags::QubitReset,
1397 LanguageFeatures::default(),
1398 store,
1399 &[(std_id, None)],
1400 );
1401
1402 match result {
1403 Ok(_) => panic!("Expected error, got interpreter."),
1404 Err(errors) => is_error(
1405 &errors,
1406 &expect![[r#"
1407 cannot use a dynamic double value
1408 [<entry>] [A.Test()]
1409 cannot use a double value as an output
1410 [<entry>] [A.Test()]
1411 cannot use a dynamic double value
1412 [test] [set x = 2.0]
1413 cannot use a dynamic double value
1414 [test] [x]
1415 "#]],
1416 ),
1417 }
1418 }
1419
1420 #[test]
1421 fn stdlib_members_can_be_accessed_from_sources() {
1422 let source = indoc! { r#"
1423 namespace Test {
1424 operation Main() : Unit {
1425 Message("hello there...")
1426 }
1427 }"#};
1428
1429 let sources = SourceMap::new([("test".into(), source.into())], None);
1430 let (std_id, store) =
1431 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1432 let dependencies = &[(std_id, None)];
1433 let mut interpreter = Interpreter::new(
1434 sources,
1435 PackageType::Lib,
1436 TargetCapabilityFlags::all(),
1437 LanguageFeatures::default(),
1438 store,
1439 dependencies,
1440 )
1441 .expect("interpreter should be created");
1442
1443 let (result, output) = line(&mut interpreter, "Test.Main()");
1444 is_unit_with_output(&result, &output, "hello there...");
1445 }
1446
1447 #[test]
1448 fn members_from_namespaced_sources_are_in_context() {
1449 let source = indoc! { r#"
1450 namespace Test {
1451 function Hello() : String {
1452 "hello there..."
1453 }
1454
1455 operation Main() : String {
1456 Hello()
1457 }
1458 }"#};
1459
1460 let sources = SourceMap::new([("test".into(), source.into())], None);
1461 let store = crate::PackageStore::new(crate::compile::core());
1462 let mut interpreter = Interpreter::new(
1463 sources,
1464 PackageType::Lib,
1465 TargetCapabilityFlags::all(),
1466 LanguageFeatures::default(),
1467 store,
1468 &[],
1469 )
1470 .expect("interpreter should be created");
1471
1472 let (result, output) = line(&mut interpreter, "Test.Hello()");
1473 is_only_value(&result, &output, &Value::String("hello there...".into()));
1474 let (result, output) = line(&mut interpreter, "Test.Main()");
1475 is_only_value(&result, &output, &Value::String("hello there...".into()));
1476 }
1477
1478 #[test]
1479 fn multiple_files_are_loaded_from_sources_into_eval_context() {
1480 let sources: [(Arc<str>, Arc<str>); 2] = [
1481 (
1482 "a.qs".into(),
1483 r#"
1484 namespace Test {
1485 function Hello() : String {
1486 "hello there..."
1487 }
1488 }"#
1489 .into(),
1490 ),
1491 (
1492 "b.qs".into(),
1493 r#"
1494 namespace Test2 {
1495 open Test;
1496 @EntryPoint()
1497 operation Main() : String {
1498 Hello();
1499 Hello()
1500 }
1501 }"#
1502 .into(),
1503 ),
1504 ];
1505
1506 let sources = SourceMap::new(sources, None);
1507 let store = crate::PackageStore::new(crate::compile::core());
1508 let debugger = Debugger::new(
1509 sources,
1510 TargetCapabilityFlags::all(),
1511 Encoding::Utf8,
1512 LanguageFeatures::default(),
1513 store,
1514 &[],
1515 )
1516 .expect("debugger should be created");
1517 let bps = debugger.get_breakpoints("a.qs");
1518 assert_eq!(1, bps.len());
1519 let bps = debugger.get_breakpoints("b.qs");
1520 assert_eq!(2, bps.len());
1521 }
1522
1523 #[test]
1524 fn debugger_simple_execution_succeeds() {
1525 let source = indoc! { r#"
1526 namespace Test {
1527 function Hello() : Unit {
1528 Message("hello there...");
1529 }
1530
1531 @EntryPoint()
1532 operation Main() : Unit {
1533 Hello()
1534 }
1535 }"#};
1536
1537 let sources = SourceMap::new([("test".into(), source.into())], None);
1538 let (std_id, store) =
1539 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1540 let mut debugger = Debugger::new(
1541 sources,
1542 TargetCapabilityFlags::all(),
1543 Encoding::Utf8,
1544 LanguageFeatures::default(),
1545 store,
1546 &[(std_id, None)],
1547 )
1548 .expect("debugger should be created");
1549 let (result, output) = entry(&mut debugger.interpreter);
1550 is_unit_with_output_eval_entry(&result, &output, "hello there...");
1551 }
1552
1553 #[test]
1554 fn debugger_execution_with_call_to_library_succeeds() {
1555 let source = indoc! { r#"
1556 namespace Test {
1557 import Std.Math.*;
1558 @EntryPoint()
1559 operation Main() : Int {
1560 Binom(31, 7)
1561 }
1562 }"#};
1563
1564 let sources = SourceMap::new([("test".into(), source.into())], None);
1565 let (std_id, store) =
1566 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1567 let mut debugger = Debugger::new(
1568 sources,
1569 TargetCapabilityFlags::all(),
1570 Encoding::Utf8,
1571 LanguageFeatures::default(),
1572 store,
1573 &[(std_id, None)],
1574 )
1575 .expect("debugger should be created");
1576 let (result, output) = entry(&mut debugger.interpreter);
1577 is_only_value(&result, &output, &Value::Int(2_629_575));
1578 }
1579
1580 #[test]
1581 fn debugger_execution_with_early_return_succeeds() {
1582 let source = indoc! { r#"
1583 namespace Test {
1584 import Std.Arrays.*;
1585
1586 operation Max20(i : Int) : Int {
1587 if (i > 20) {
1588 return 20;
1589 }
1590 return i;
1591 }
1592
1593 @EntryPoint()
1594 operation Main() : Int[] {
1595 ForEach(Max20, [10, 20, 30, 40, 50])
1596 }
1597 }"#};
1598
1599 let sources = SourceMap::new([("test".into(), source.into())], None);
1600 let (std_id, store) =
1601 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1602 let mut debugger = Debugger::new(
1603 sources,
1604 TargetCapabilityFlags::all(),
1605 Encoding::Utf8,
1606 LanguageFeatures::default(),
1607 store,
1608 &[(std_id, None)],
1609 )
1610 .expect("debugger should be created");
1611
1612 let (result, output) = entry(&mut debugger.interpreter);
1613 is_only_value(
1614 &result,
1615 &output,
1616 &Value::Array(
1617 vec![
1618 Value::Int(10),
1619 Value::Int(20),
1620 Value::Int(20),
1621 Value::Int(20),
1622 Value::Int(20),
1623 ]
1624 .into(),
1625 ),
1626 );
1627 }
1628
1629 #[test]
1630 fn multiple_namespaces_are_loaded_from_sources_into_eval_context() {
1631 let source = indoc! { r#"
1632 namespace Test {
1633 function Hello() : String {
1634 "hello there..."
1635 }
1636 }
1637 namespace Test2 {
1638 open Test;
1639 operation Main() : String {
1640 Hello()
1641 }
1642 }"#};
1643
1644 let sources = SourceMap::new([("test".into(), source.into())], None);
1645 let store = crate::PackageStore::new(crate::compile::core());
1646 let mut interpreter = Interpreter::new(
1647 sources,
1648 PackageType::Lib,
1649 TargetCapabilityFlags::all(),
1650 LanguageFeatures::default(),
1651 store,
1652 &[],
1653 )
1654 .expect("interpreter should be created");
1655 let (result, output) = line(&mut interpreter, "Test.Hello()");
1656 is_only_value(&result, &output, &Value::String("hello there...".into()));
1657 let (result, output) = line(&mut interpreter, "Test2.Main()");
1658 is_only_value(&result, &output, &Value::String("hello there...".into()));
1659 }
1660
1661 #[test]
1662 fn runtime_error_from_stdlib() {
1663 let sources = SourceMap::new(
1664 [(
1665 "test".into(),
1666 "namespace Foo {
1667 operation Bar(): Unit {
1668 let x = -1;
1669 use qs = Qubit[x];
1670 }
1671 }
1672 "
1673 .into(),
1674 )],
1675 Some("Foo.Bar()".into()),
1676 );
1677
1678 let store = crate::PackageStore::new(crate::compile::core());
1679 let mut interpreter = Interpreter::new(
1680 sources,
1681 PackageType::Lib,
1682 TargetCapabilityFlags::all(),
1683 LanguageFeatures::default(),
1684 store,
1685 &[],
1686 )
1687 .expect("interpreter should be created");
1688
1689 let (result, output) = entry(&mut interpreter);
1690 is_only_error(
1691 &result,
1692 &output,
1693 &expect![[r#"
1694 runtime error: program failed: Cannot allocate qubit array with a negative length
1695 explicit fail [qsharp-library-source:core/qir.qs] [fail "Cannot allocate qubit array with a negative length"]
1696 "#]],
1697 );
1698 }
1699
1700 #[test]
1701 fn interpreter_can_be_created_from_ast() {
1702 let sources = SourceMap::new(
1703 [(
1704 "test".into(),
1705 "namespace A {
1706 operation B(): Result {
1707 use qs = Qubit[2];
1708 X(qs[0]);
1709 CNOT(qs[0], qs[1]);
1710 let res = Measure([PauliZ, PauliZ], qs[...1]);
1711 ResetAll(qs);
1712 res
1713 }
1714 }
1715 "
1716 .into(),
1717 )],
1718 Some("A.B()".into()),
1719 );
1720
1721 let (package_type, capabilities, language_features) = (
1722 PackageType::Lib,
1723 TargetCapabilityFlags::all(),
1724 LanguageFeatures::default(),
1725 );
1726
1727 let mut store = crate::PackageStore::new(crate::compile::core());
1728 let dependencies = vec![(
1729 store.insert(crate::compile::std(&store, capabilities)),
1730 None,
1731 )];
1732
1733 let (mut unit, errors) = crate::compile::compile(
1734 &store,
1735 &dependencies,
1736 sources,
1737 package_type,
1738 capabilities,
1739 language_features,
1740 );
1741 unit.expose();
1742 for e in &errors {
1743 eprintln!("{e:?}");
1744 }
1745 assert!(errors.is_empty(), "compilation failed: {}", errors[0]);
1746 let package_id = store.insert(unit);
1747
1748 let mut interpreter = Interpreter::from(
1749 store,
1750 package_id,
1751 capabilities,
1752 language_features,
1753 &dependencies,
1754 )
1755 .expect("interpreter should be created");
1756 let (result, output) = entry(&mut interpreter);
1757 is_only_value(
1758 &result,
1759 &output,
1760 &Value::Result(qsc_eval::val::Result::Val(false)),
1761 );
1762 }
1763
1764 #[test]
1765 fn ast_fragments_can_be_evaluated() {
1766 let sources = SourceMap::new(
1767 [(
1768 "test".into(),
1769 "namespace A {
1770 operation B(): Result {
1771 use qs = Qubit[2];
1772 X(qs[0]);
1773 CNOT(qs[0], qs[1]);
1774 let res = Measure([PauliZ, PauliZ], qs[...1]);
1775 ResetAll(qs);
1776 res
1777 }
1778 }
1779 "
1780 .into(),
1781 )],
1782 None,
1783 );
1784 let (std_id, store) =
1785 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1786 let mut interpreter = Interpreter::new(
1787 sources,
1788 PackageType::Lib,
1789 TargetCapabilityFlags::all(),
1790 LanguageFeatures::default(),
1791 store,
1792 &[(std_id, None)],
1793 )
1794 .expect("interpreter should be created");
1795
1796 let package = get_package_for_call("A", "B");
1797 let (result, output) = fragment(&mut interpreter, "A.B()", package);
1798 is_only_value(
1799 &result,
1800 &output,
1801 &Value::Result(qsc_eval::val::Result::Val(false)),
1802 );
1803 }
1804
1805 #[test]
1806 fn ast_fragments_evaluation_returns_runtime_errors() {
1807 let sources = SourceMap::new(
1808 [(
1809 "test".into(),
1810 "namespace A {
1811 operation B(): Int {
1812 42 / 0
1813 }
1814 }
1815 "
1816 .into(),
1817 )],
1818 None,
1819 );
1820 let (std_id, store) =
1821 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
1822 let mut interpreter = Interpreter::new(
1823 sources,
1824 PackageType::Lib,
1825 TargetCapabilityFlags::all(),
1826 LanguageFeatures::default(),
1827 store,
1828 &[(std_id, None)],
1829 )
1830 .expect("interpreter should be created");
1831
1832 let package = get_package_for_call("A", "B");
1833 let (result, output) = fragment(&mut interpreter, "A.B()", package);
1834 is_only_error(
1835 &result,
1836 &output,
1837 &expect![[r#"
1838 runtime error: division by zero
1839 cannot divide by zero [test] [0]
1840 "#]],
1841 );
1842 }
1843
1844 fn get_package_for_call(ns: &str, name: &str) -> crate::ast::Package {
1845 let args = Expr {
1846 id: NodeId::default(),
1847 span: Span::default(),
1848 kind: Box::new(ExprKind::Tuple(Box::new([]))),
1849 };
1850 let path = Path {
1851 id: NodeId::default(),
1852 span: Span::default(),
1853 segments: Some(
1854 std::iter::once(qsc_ast::ast::Ident {
1855 id: NodeId::default(),
1856 span: Span::default(),
1857 name: ns.into(),
1858 })
1859 .collect(),
1860 ),
1861 name: Box::new(qsc_ast::ast::Ident {
1862 id: NodeId::default(),
1863 span: Span::default(),
1864 name: name.into(),
1865 }),
1866 };
1867 let path_expr = Expr {
1868 id: NodeId::default(),
1869 span: Span::default(),
1870 kind: Box::new(ExprKind::Path(PathKind::Ok(Box::new(path)))),
1871 };
1872 let expr = Expr {
1873 id: NodeId::default(),
1874 span: Span::default(),
1875 kind: Box::new(ExprKind::Call(Box::new(path_expr), Box::new(args))),
1876 };
1877 let stmt = Stmt {
1878 id: NodeId::default(),
1879 span: Span::default(),
1880 kind: Box::new(StmtKind::Expr(Box::new(expr))),
1881 };
1882 let top_level = TopLevelNode::Stmt(Box::new(stmt));
1883 Package {
1884 id: NodeId::default(),
1885 nodes: vec![top_level].into_boxed_slice(),
1886 entry: None,
1887 }
1888 }
1889 }
1890}
1891