microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/telemmocks

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc/src/interpret/tests.rs

1891lines · modecode

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