microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billt/mac-intel-cryptography

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc/src/interpret/tests.rs

2922lines · 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::source::SourceMap;
9 use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
10 use qsc_eval::{output::CursorReceiver, val::Value};
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 let res = interpreter.run(
27 &mut receiver,
28 Some(expr),
29 None,
30 None,
31 None,
32 None,
33 Default::default(),
34 );
35 (res, receiver.dump())
36 }
37
38 fn entry(interpreter: &mut Interpreter) -> (InterpretResult, String) {
39 let mut cursor = Cursor::new(Vec::<u8>::new());
40 let mut receiver = CursorReceiver::new(&mut cursor);
41 (interpreter.eval_entry(&mut receiver), receiver.dump())
42 }
43
44 fn fragment(
45 interpreter: &mut Interpreter,
46 fragments: &str,
47 package: crate::ast::Package,
48 ) -> (InterpretResult, String) {
49 let mut cursor = Cursor::new(Vec::<u8>::new());
50 let mut receiver = CursorReceiver::new(&mut cursor);
51 let result = interpreter.eval_ast_fragments(&mut receiver, fragments, package);
52 (result, receiver.dump())
53 }
54
55 fn invoke(
56 interpreter: &mut Interpreter,
57 callable: &str,
58 args: Value,
59 ) -> (InterpretResult, String) {
60 let mut cursor = Cursor::new(Vec::<u8>::new());
61 let mut receiver = CursorReceiver::new(&mut cursor);
62 let callable = match interpreter.eval_fragments(&mut receiver, callable) {
63 Ok(val) => val,
64 Err(e) => return (Err(e), receiver.dump()),
65 };
66 let result = interpreter.invoke(&mut receiver, callable, args);
67 (result, receiver.dump())
68 }
69
70 mod without_sources {
71 use std::rc::Rc;
72
73 use expect_test::expect;
74 use indoc::indoc;
75
76 use super::*;
77
78 mod without_stdlib {
79 use qsc_data_structures::source::SourceMap;
80 use qsc_passes::PackageType;
81
82 use super::*;
83
84 #[test]
85 fn stdlib_members_should_be_unavailable() {
86 let store = crate::PackageStore::new(crate::compile::core());
87 let mut interpreter = Interpreter::new(
88 SourceMap::default(),
89 PackageType::Lib,
90 TargetCapabilityFlags::all(),
91 LanguageFeatures::default(),
92 store,
93 &[],
94 )
95 .expect("interpreter should be created");
96
97 let (result, output) = line(&mut interpreter, "Message(\"_\")");
98 is_only_error(
99 &result,
100 &output,
101 &expect![[r#"
102 name error: `Message` not found
103 [line_0] [Message]
104 "#]],
105 );
106 }
107 }
108
109 #[test]
110 fn stdlib_members_should_be_available() {
111 let mut interpreter = get_interpreter();
112 let (result, output) = line(&mut interpreter, "Message(\"_\")");
113 is_unit_with_output(&result, &output, "_");
114 }
115
116 #[test]
117 fn core_members_should_be_available() {
118 let mut interpreter = get_interpreter();
119 let (result, output) = line(&mut interpreter, "Length([1, 2, 3])");
120 is_only_value(&result, &output, &Value::Int(3));
121 }
122
123 #[test]
124 fn let_bindings_update_interpreter() {
125 let mut interpreter = get_interpreter();
126 line(&mut interpreter, "let y = 7;")
127 .0
128 .expect("line should succeed");
129 let (result, output) = line(&mut interpreter, "y");
130 is_only_value(&result, &output, &Value::Int(7));
131 }
132
133 #[test]
134 fn let_bindings_can_be_shadowed() {
135 let mut interpreter = get_interpreter();
136
137 let (result, output) = line(&mut interpreter, "let y = 7;");
138 is_only_value(&result, &output, &Value::unit());
139
140 let (result, output) = line(&mut interpreter, "y");
141 is_only_value(&result, &output, &Value::Int(7));
142
143 let (result, output) = line(&mut interpreter, "let y = \"Hello\";");
144 is_only_value(&result, &output, &Value::unit());
145
146 let (result, output) = line(&mut interpreter, "y");
147 is_only_value(&result, &output, &Value::String("Hello".into()));
148 }
149
150 #[test]
151 fn invalid_statements_return_error() {
152 let mut interpreter = get_interpreter();
153
154 let (result, output) = line(&mut interpreter, "let y = 7");
155 is_only_error(
156 &result,
157 &output,
158 &expect![[r#"
159 syntax error: expected `;`, found EOF
160 [line_0] []
161 "#]],
162 );
163
164 let (result, output) = line(&mut interpreter, "y");
165 is_only_error(
166 &result,
167 &output,
168 &expect![[r#"
169 name error: `y` not found
170 [line_1] [y]
171 "#]],
172 );
173 }
174
175 #[test]
176 fn invalid_statements_and_unbound_vars_return_error_on_immutable_usage() {
177 let mut interpreter = get_interpreter();
178
179 let (result, output) = line(&mut interpreter, "let y = x;");
180 is_only_error(
181 &result,
182 &output,
183 &expect![[r#"
184 name error: `x` not found
185 [line_0] [x]
186 type error: insufficient type information to infer type
187 [line_0] [y]
188 "#]],
189 );
190
191 let (result, output) = line(&mut interpreter, "y");
192 is_only_error(
193 &result,
194 &output,
195 &expect![[r#"
196 runtime error: name is not bound
197 [line_1] [y]
198 "#]],
199 );
200 }
201
202 #[test]
203 fn invalid_statements_and_unbound_vars_return_error_on_mutable_update() {
204 let mut interpreter = get_interpreter();
205
206 let (result, output) = line(&mut interpreter, "mutable y = x;");
207 is_only_error(
208 &result,
209 &output,
210 &expect![[r#"
211 name error: `x` not found
212 [line_0] [x]
213 type error: insufficient type information to infer type
214 [line_0] [y]
215 "#]],
216 );
217
218 let (result, output) = line(&mut interpreter, "y = 3");
219 is_only_error(
220 &result,
221 &output,
222 &expect![[r#"
223 cannot update immutable variable
224 [line_1] [y]
225 "#]],
226 );
227 }
228
229 #[test]
230 fn invalid_statements_and_unbound_vars_return_error_on_immutable_usage_with_rca() {
231 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
232
233 let (result, output) = line(&mut interpreter, "let y = x;");
234 is_only_error(
235 &result,
236 &output,
237 &expect![[r#"
238 name error: `x` not found
239 [line_0] [x]
240 type error: insufficient type information to infer type
241 [line_0] [y]
242 "#]],
243 );
244
245 let (result, output) = line(&mut interpreter, "y");
246 is_only_error(
247 &result,
248 &output,
249 &expect![[r#"
250 runtime error: name is not bound
251 [line_1] [y]
252 "#]],
253 );
254 }
255
256 #[test]
257 fn invalid_statements_and_unbound_vars_return_error_on_mutable_update_with_rca() {
258 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
259
260 let (result, output) = line(&mut interpreter, "mutable y = x;");
261 is_only_error(
262 &result,
263 &output,
264 &expect![[r#"
265 name error: `x` not found
266 [line_0] [x]
267 type error: insufficient type information to infer type
268 [line_0] [y]
269 "#]],
270 );
271
272 let (result, output) = line(&mut interpreter, "y = 3");
273 is_only_error(
274 &result,
275 &output,
276 &expect![[r#"
277 cannot update immutable variable
278 [line_1] [y]
279 "#]],
280 );
281 }
282
283 #[test]
284 fn failing_statements_return_early_error() {
285 let mut interpreter = get_interpreter();
286 let (result, output) = line(&mut interpreter, "let y = 7;y/0;y");
287 is_only_error(
288 &result,
289 &output,
290 &expect![[r#"
291 runtime error: division by zero
292 cannot divide by zero [line_0] [0]
293 "#]],
294 );
295 }
296
297 #[test]
298 fn passes_are_run_on_incremental() {
299 let mut interpreter = get_interpreter();
300 let (result, output) = line(
301 &mut interpreter,
302 "within {Message(\"A\");} apply {Message(\"B\");}",
303 );
304 is_unit_with_output(&result, &output, "A\nB\nA");
305 }
306
307 #[test]
308 fn declare_function() {
309 let mut interpreter = get_interpreter();
310 let (result, output) = line(&mut interpreter, "function Foo() : Int { 2 }");
311 is_only_value(&result, &output, &Value::unit());
312 let (result, output) = line(&mut interpreter, "Foo()");
313 is_only_value(&result, &output, &Value::Int(2));
314 }
315
316 #[test]
317 fn invalid_declare_function_and_unbound_call_return_error() {
318 let mut interpreter = get_interpreter();
319 let (result, output) = line(&mut interpreter, "function Foo() : Int { invalid }");
320 is_only_error(
321 &result,
322 &output,
323 &expect![[r#"
324 name error: `invalid` not found
325 [line_0] [invalid]
326 "#]],
327 );
328 let (result, output) = line(&mut interpreter, "Foo()");
329 is_only_error(
330 &result,
331 &output,
332 &expect![[r#"
333 runtime error: name is not bound
334 [line_1] [Foo]
335 "#]],
336 );
337 }
338
339 #[test]
340 fn declare_function_call_same_line() {
341 let mut interpreter = get_interpreter();
342 let (result, output) = line(&mut interpreter, "function Foo() : Int { 2 }; Foo()");
343 is_only_value(&result, &output, &Value::Int(2));
344 }
345
346 #[test]
347 fn let_binding_function_declaration_call_same_line() {
348 let mut interpreter = get_interpreter();
349 let (result, output) = line(
350 &mut interpreter,
351 "let x = 1; function Foo() : Int { 2 }; Foo() + 1",
352 );
353 is_only_value(&result, &output, &Value::Int(3));
354 }
355
356 #[test]
357 fn nested_function() {
358 let mut interpreter = get_interpreter();
359 let (result, output) = line(
360 &mut interpreter,
361 "function Foo() : Int { function Bar() : Int { 1 }; Bar() + 1 }; Foo() + 1",
362 );
363 is_only_value(&result, &output, &Value::Int(3));
364 }
365
366 #[test]
367 fn open_namespace() {
368 let mut interpreter = get_interpreter();
369 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
370 is_only_value(&result, &output, &Value::unit());
371 let (result, output) = line(&mut interpreter, "DumpMachine()");
372 is_unit_with_output(&result, &output, "STATE:\nNo qubits allocated");
373 }
374
375 #[test]
376 fn open_namespace_call_same_line() {
377 let mut interpreter = get_interpreter();
378 let (result, output) = line(
379 &mut interpreter,
380 "open Microsoft.Quantum.Diagnostics; DumpMachine()",
381 );
382 is_unit_with_output(&result, &output, "STATE:\nNo qubits allocated");
383 }
384
385 #[test]
386 fn declare_namespace_call() {
387 let mut interpreter = get_interpreter();
388 let (result, output) = line(
389 &mut interpreter,
390 "namespace Foo { function Bar() : Int { 5 } }",
391 );
392 is_only_value(&result, &output, &Value::unit());
393 let (result, output) = line(&mut interpreter, "Foo.Bar()");
394 is_only_value(&result, &output, &Value::Int(5));
395 }
396
397 #[test]
398 fn declare_namespace_open_call() {
399 let mut interpreter = get_interpreter();
400 let (result, output) = line(
401 &mut interpreter,
402 "namespace Foo { function Bar() : Int { 5 } }",
403 );
404 is_only_value(&result, &output, &Value::unit());
405 let (result, output) = line(&mut interpreter, "open Foo;");
406 is_only_value(&result, &output, &Value::unit());
407 let (result, output) = line(&mut interpreter, "Bar()");
408 is_only_value(&result, &output, &Value::Int(5));
409 }
410
411 #[test]
412 fn declare_namespace_open_call_same_line() {
413 let mut interpreter = get_interpreter();
414 let (result, output) = line(
415 &mut interpreter,
416 "namespace Foo { function Bar() : Int { 5 } } open Foo; Bar()",
417 );
418 is_only_value(&result, &output, &Value::Int(5));
419 }
420
421 #[test]
422 fn mix_stmts_and_namespace_same_line() {
423 let mut interpreter = get_interpreter();
424 let (result, output) = line(
425 &mut interpreter,
426 "Message(\"before\"); namespace Foo { function Bar() : Int { 5 } } Message(\"after\")",
427 );
428 is_unit_with_output(&result, &output, "before\nafter");
429 }
430
431 #[test]
432 fn assign_array_index_expr_eval_in_order() {
433 let mut interpreter = get_interpreter();
434 let (result, output) = line(
435 &mut interpreter,
436 "mutable arr = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]];",
437 );
438 is_only_value(&result, &output, &Value::unit());
439 let (result, output) = line(
440 &mut interpreter,
441 "arr[{ Message(\"First Index\"); 0 }][{ Message(\"Second Index\"); 1 }][{ Message(\"Third Index\"); 1 }] = 13;",
442 );
443 is_unit_with_output(&result, &output, "First Index\nSecond Index\nThird Index");
444 let (result, output) = line(&mut interpreter, "arr");
445 is_only_value(
446 &result,
447 &output,
448 &Value::Array(Rc::new(vec![
449 Value::Array(Rc::new(vec![
450 Value::Array(Rc::new(vec![Value::Int(0), Value::Int(1)])),
451 Value::Array(Rc::new(vec![Value::Int(2), Value::Int(13)])),
452 ])),
453 Value::Array(Rc::new(vec![
454 Value::Array(Rc::new(vec![Value::Int(4), Value::Int(5)])),
455 Value::Array(Rc::new(vec![Value::Int(6), Value::Int(7)])),
456 ])),
457 ])),
458 );
459 }
460
461 #[test]
462 fn global_qubits() {
463 let mut interpreter = get_interpreter();
464 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
465 is_only_value(&result, &output, &Value::unit());
466 let (result, output) = line(&mut interpreter, "DumpMachine()");
467 is_unit_with_output(&result, &output, "STATE:\nNo qubits allocated");
468 let (result, output) = line(&mut interpreter, "use (q0, qs) = (Qubit(), Qubit[3]);");
469 is_only_value(&result, &output, &Value::unit());
470 let (result, output) = line(&mut interpreter, "DumpMachine()");
471 is_unit_with_output(&result, &output, "STATE:\n|0000⟩: 1+0i");
472 let (result, output) = line(&mut interpreter, "X(q0); X(qs[1]);");
473 is_only_value(&result, &output, &Value::unit());
474 let (result, output) = line(&mut interpreter, "DumpMachine()");
475 is_unit_with_output(&result, &output, "STATE:\n|1010⟩: 1+0i");
476 }
477
478 #[test]
479 fn ambiguous_type_error_in_top_level_stmts() {
480 let mut interpreter = get_interpreter();
481 let (result, output) = line(&mut interpreter, "let x = [];");
482 is_only_error(
483 &result,
484 &output,
485 &expect![[r#"
486 type error: insufficient type information to infer type
487 [line_0] [[]]
488 "#]],
489 );
490 let (result, output) = line(&mut interpreter, "let x = []; let y = [0] + x;");
491 is_only_value(&result, &output, &Value::unit());
492 let (result, output) = line(&mut interpreter, "function Foo() : Unit { let x = []; }");
493 is_only_error(
494 &result,
495 &output,
496 &expect![[r#"
497 type error: insufficient type information to infer type
498 [line_2] [[]]
499 "#]],
500 );
501 }
502
503 #[test]
504 fn resolved_type_persists_across_stmts() {
505 let mut interpreter = get_interpreter();
506 let (result, output) = line(&mut interpreter, "let x = []; let y = [0] + x;");
507 is_only_value(&result, &output, &Value::unit());
508 let (result, output) = line(&mut interpreter, "let z = [0.0] + x;");
509 is_only_error(
510 &result,
511 &output,
512 &expect![[r#"
513 type error: expected Double, found Int
514 [line_1] [x]
515 "#]],
516 );
517 }
518
519 #[test]
520 fn incremental_lambas_work() {
521 let mut interpreter = get_interpreter();
522 let (result, output) = line(&mut interpreter, "let x = 1; let f = (y) -> x + y;");
523 is_only_value(&result, &output, &Value::unit());
524 let (result, output) = line(&mut interpreter, "f(1)");
525 is_only_value(&result, &output, &Value::Int(2));
526 }
527
528 #[test]
529 fn mutability_persists_across_stmts() {
530 let mut interpreter = get_interpreter();
531 let (result, output) = line(
532 &mut interpreter,
533 "mutable x : Int[] = []; let y : Int[] = [];",
534 );
535 is_only_value(&result, &output, &Value::unit());
536 let (result, output) = line(&mut interpreter, "set x += [0];");
537 is_only_value(&result, &output, &Value::unit());
538 let (result, output) = line(&mut interpreter, "set y += [0];");
539 is_only_error(
540 &result,
541 &output,
542 &expect![[r#"
543 cannot update immutable variable
544 [line_2] [y]
545 "#]],
546 );
547 let (result, output) = line(&mut interpreter, "let lam = () -> y + [0];");
548 is_only_value(&result, &output, &Value::unit());
549 let (result, output) = line(&mut interpreter, "let lam = () -> x + [0];");
550 is_only_error(
551 &result,
552 &output,
553 &expect![[r#"
554 lambdas cannot close over mutable variables
555 [line_4] [() -> x + [0]]
556 "#]],
557 );
558 }
559
560 #[test]
561 fn runtime_error_across_lines() {
562 let mut interpreter = get_interpreter();
563 let (result, output) = line(
564 &mut interpreter,
565 "operation Main() : Unit { Microsoft.Quantum.Random.DrawRandomInt(2,1); }",
566 );
567 is_only_value(&result, &output, &Value::unit());
568 let (result, output) = line(&mut interpreter, "Main()");
569 is_only_error(
570 &result,
571 &output,
572 &expect![[r#"
573 runtime error: empty range
574 the range cannot be empty [line_0] [(2,1)]
575 "#]],
576 );
577 }
578
579 #[test]
580 fn compiler_error_across_lines() {
581 let mut interpreter = get_interpreter();
582 let (result, output) = line(
583 &mut interpreter,
584 "namespace Other { operation DumpMachine() : Unit { } }",
585 );
586 is_only_value(&result, &output, &Value::unit());
587 let (result, output) = line(&mut interpreter, "open Other;");
588 is_only_value(&result, &output, &Value::unit());
589 let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;");
590 is_only_value(&result, &output, &Value::unit());
591 let (result, output) = line(&mut interpreter, "DumpMachine();");
592 is_only_error(
593 &result,
594 &output,
595 &expect![[r#"
596 name error: `DumpMachine` could refer to the item in `Other` or `Std.Diagnostics`
597 ambiguous name [line_3] [DumpMachine]
598 found in this namespace [line_1] [Other]
599 and also in this namespace [line_2] [Std.Diagnostics]
600 "#]],
601 );
602 }
603
604 #[test]
605 fn runtime_error_from_stdlib() {
606 let mut interpreter = get_interpreter();
607 let (result, output) = line(&mut interpreter, "use q = Qubit(); CNOT(q,q)");
608 is_only_error(
609 &result,
610 &output,
611 &expect![[r#"
612 runtime error: qubits in invocation are not unique
613 [qsharp-library-source:Std/Intrinsic.qs] [(control, target)]
614 "#]],
615 );
616 }
617
618 #[test]
619 fn items_usable_before_definition() {
620 let mut interpreter = get_interpreter();
621 let (result, output) = line(
622 &mut interpreter,
623 indoc! {r#"
624 function A() : Unit {
625 B();
626 }
627 function B() : Unit {}
628 A()
629 "#},
630 );
631 is_only_value(&result, &output, &Value::unit());
632 }
633
634 #[test]
635 fn items_usable_before_definition_top_level() {
636 let mut interpreter = get_interpreter();
637 let (result, output) = line(
638 &mut interpreter,
639 indoc! {r#"
640 B();
641 function B() : Unit {}
642 "#},
643 );
644 is_only_value(&result, &output, &Value::unit());
645 }
646
647 #[test]
648 fn interpreter_without_sources_has_no_items() {
649 let interpreter = get_interpreter();
650 let items = interpreter.source_globals();
651 assert!(items.is_empty());
652 }
653
654 #[test]
655 fn fragment_without_items_has_no_items() {
656 let mut interpreter = get_interpreter();
657 let (result, output) = line(&mut interpreter, "()");
658 is_only_value(&result, &output, &Value::unit());
659 let items = interpreter.user_globals();
660 assert!(items.is_empty());
661 }
662
663 #[test]
664 fn fragment_defining_items_has_items() {
665 let mut interpreter = get_interpreter();
666 let (result, output) = line(
667 &mut interpreter,
668 indoc! {r#"
669 function Foo() : Int { 2 }
670 function Bar() : Int { 3 }
671 "#},
672 );
673 is_only_value(&result, &output, &Value::unit());
674 let items = interpreter.user_globals();
675 assert_eq!(items.len(), 2);
676 // No namespace for top-level items
677 assert!(items[0].0.is_empty());
678 expect![[r#"
679 "Foo"
680 "#]]
681 .assert_debug_eq(&items[0].1);
682 // No namespace for top-level items
683 assert!(items[1].0.is_empty());
684 expect![[r#"
685 "Bar"
686 "#]]
687 .assert_debug_eq(&items[1].1);
688 }
689
690 #[test]
691 fn fragment_defining_items_with_namespace_has_items() {
692 let mut interpreter = get_interpreter();
693 let (result, output) = line(
694 &mut interpreter,
695 indoc! {r#"
696 namespace Foo {
697 function Bar() : Int { 3 }
698 }
699 "#},
700 );
701 is_only_value(&result, &output, &Value::unit());
702 let items = interpreter.user_globals();
703 assert_eq!(items.len(), 1);
704 expect![[r#"
705 [
706 "Foo",
707 ]
708 "#]]
709 .assert_debug_eq(&items[0].0);
710 expect![[r#"
711 "Bar"
712 "#]]
713 .assert_debug_eq(&items[0].1);
714 }
715
716 #[test]
717 fn fragments_defining_items_add_to_existing_items() {
718 let mut interpreter = get_interpreter();
719 let (result, output) = line(
720 &mut interpreter,
721 indoc! {r#"
722 function Foo() : Int { 2 }
723 function Bar() : Int { 3 }
724 "#},
725 );
726 is_only_value(&result, &output, &Value::unit());
727 let items = interpreter.user_globals();
728 assert_eq!(items.len(), 2);
729 let (result, output) = line(
730 &mut interpreter,
731 indoc! {r#"
732 function Baz() : Int { 4 }
733 function Qux() : Int { 5 }
734 "#},
735 );
736 is_only_value(&result, &output, &Value::unit());
737 let items = interpreter.user_globals();
738 assert_eq!(items.len(), 4);
739 // No namespace for top-level items
740 assert!(items[0].0.is_empty());
741 expect![[r#"
742 "Foo"
743 "#]]
744 .assert_debug_eq(&items[0].1);
745 // No namespace for top-level items
746 assert!(items[1].0.is_empty());
747 expect![[r#"
748 "Bar"
749 "#]]
750 .assert_debug_eq(&items[1].1);
751 // No namespace for top-level items
752 assert!(items[2].0.is_empty());
753 expect![[r#"
754 "Baz"
755 "#]]
756 .assert_debug_eq(&items[2].1);
757 // No namespace for top-level items
758 assert!(items[3].0.is_empty());
759 expect![[r#"
760 "Qux"
761 "#]]
762 .assert_debug_eq(&items[3].1);
763 }
764
765 #[test]
766 fn invoke_callable_without_args_succeeds() {
767 let mut interpreter = get_interpreter();
768 let (result, output) = invoke(
769 &mut interpreter,
770 "Std.Diagnostics.DumpMachine",
771 Value::unit(),
772 );
773 is_unit_with_output(&result, &output, "STATE:\nNo qubits allocated");
774 }
775
776 #[test]
777 fn invoke_callable_with_args_succeeds() {
778 let mut interpreter = get_interpreter();
779 let (result, output) = invoke(
780 &mut interpreter,
781 "Message",
782 Value::String("Hello, World!".into()),
783 );
784 is_unit_with_output(&result, &output, "Hello, World!");
785 }
786
787 #[test]
788 fn invoke_lambda_with_capture_succeeds() {
789 let mut interpreter = get_interpreter();
790 let (result, output) = line(&mut interpreter, "let x = 1; let f = y -> x + y;");
791 is_only_value(&result, &output, &Value::unit());
792 let (result, output) = invoke(&mut interpreter, "f", Value::Int(2));
793 is_only_value(&result, &output, &Value::Int(3));
794 }
795
796 #[test]
797 fn invoke_lambda_with_capture_in_callable_expr_succeeds() {
798 let mut interpreter = get_interpreter();
799 let (result, output) = invoke(
800 &mut interpreter,
801 "{let x = 1; let f = y -> x + y; f}",
802 Value::Int(2),
803 );
804 is_only_value(&result, &output, &Value::Int(3));
805 }
806
807 #[test]
808 fn callables_failing_profile_validation_are_not_registered() {
809 let mut interpreter =
810 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
811 let (result, output) = line(
812 &mut interpreter,
813 indoc! {r#"
814 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
815 "#},
816 );
817 is_only_error(
818 &result,
819 &output,
820 &expect![[r#"
821 cannot use a dynamic integer value
822 [line_0] [set x = 2]
823 cannot use a dynamic integer value
824 [line_0] [x]
825 "#]],
826 );
827 // do something innocuous
828 let (result, output) = line(&mut interpreter, indoc! {r#"Foo()"#});
829 // since the callable wasn't registered, this will return an unbound name error.
830 is_only_error(
831 &result,
832 &output,
833 &expect![[r#"
834 runtime error: name is not bound
835 [line_1] [Foo]
836 "#]],
837 );
838 }
839
840 #[test]
841 fn callables_failing_profile_validation_also_fail_qir_generation() {
842 let mut interpreter =
843 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
844 let (result, output) = line(
845 &mut interpreter,
846 indoc! {r#"
847 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
848 "#},
849 );
850 is_only_error(
851 &result,
852 &output,
853 &expect![[r#"
854 cannot use a dynamic integer value
855 [line_0] [set x = 2]
856 cannot use a dynamic integer value
857 [line_0] [x]
858 "#]],
859 );
860 let res = interpreter.qirgen("{Foo();}");
861 expect![[r#"
862 Err(
863 [
864 PartialEvaluation(
865 WithSource {
866 sources: [
867 Source {
868 name: "<entry>",
869 contents: "{Foo();}",
870 offset: 97,
871 },
872 ],
873 error: EvaluationFailed(
874 "name is not bound",
875 PackageSpan {
876 package: PackageId(
877 3,
878 ),
879 span: Span {
880 lo: 98,
881 hi: 101,
882 },
883 },
884 ),
885 },
886 ),
887 ],
888 )
889 "#]]
890 .assert_debug_eq(&res);
891 }
892
893 #[test]
894 fn once_rca_validation_fails_following_calls_do_not_fail() {
895 let mut interpreter =
896 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
897 let (result, output) = line(
898 &mut interpreter,
899 indoc! {r#"
900 operation Foo() : Int { use q = Qubit(); mutable x = 1; if MResetZ(q) == One { set x = 2; } x }
901 "#},
902 );
903 is_only_error(
904 &result,
905 &output,
906 &expect![[r#"
907 cannot use a dynamic integer value
908 [line_0] [set x = 2]
909 cannot use a dynamic integer value
910 [line_0] [x]
911 "#]],
912 );
913 // do something innocuous
914 let (result, output) = line(
915 &mut interpreter,
916 indoc! {r#"
917 let y = 7;
918 "#},
919 );
920 is_only_value(&result, &output, &Value::unit());
921 }
922
923 #[test]
924 fn namespace_usable_before_definition() {
925 let mut interpreter = get_interpreter();
926 let (result, output) = line(
927 &mut interpreter,
928 indoc! {r#"
929 A.B();
930 namespace A {
931 function B() : Unit {}
932 }
933 "#},
934 );
935 is_only_value(&result, &output, &Value::unit());
936 }
937
938 #[test]
939 fn mutually_recursive_namespaces_work() {
940 let mut interpreter = get_interpreter();
941 let (result, output) = line(
942 &mut interpreter,
943 indoc! {r#"
944 A.B();
945 namespace A {
946 open C;
947 function B() : Unit {
948 D();
949 }
950 function E() : Unit {}
951 }
952 namespace C {
953 open A;
954 function D() : Unit {
955 E();
956 }
957 }
958 "#},
959 );
960 is_only_value(&result, &output, &Value::unit());
961 }
962
963 #[test]
964 fn local_var_valid_after_item_definition() {
965 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
966 let (result, output) = line(&mut interpreter, "let a = 1;");
967 is_only_value(&result, &output, &Value::unit());
968 let (result, output) = line(&mut interpreter, "a");
969 is_only_value(&result, &output, &Value::Int(1));
970 let (result, output) = line(
971 &mut interpreter,
972 "function B() : Int { let inner_b = 3; inner_b }",
973 );
974 is_only_value(&result, &output, &Value::unit());
975 let (result, output) = line(&mut interpreter, "B()");
976 is_only_value(&result, &output, &Value::Int(3));
977 let (result, output) = line(&mut interpreter, "let b = 2;");
978 is_only_value(&result, &output, &Value::unit());
979 let (result, output) = line(&mut interpreter, "b");
980 is_only_value(&result, &output, &Value::Int(2));
981 let (result, output) = line(&mut interpreter, "a");
982 is_only_value(&result, &output, &Value::Int(1));
983 let (result, output) = line(&mut interpreter, "B()");
984 is_only_value(&result, &output, &Value::Int(3));
985 }
986
987 #[test]
988 fn base_qirgen() {
989 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
990 let (result, output) = line(
991 &mut interpreter,
992 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
993 );
994 is_only_value(&result, &output, &Value::unit());
995 let res = interpreter.qirgen("Foo()").expect("expected success");
996 expect![[r#"
997 %Result = type opaque
998 %Qubit = type opaque
999
1000 @0 = internal constant [4 x i8] c"0_r\00"
1001
1002 define i64 @ENTRYPOINT__main() #0 {
1003 block_0:
1004 call void @__quantum__rt__initialize(i8* null)
1005 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1006 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1007 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1008 ret i64 0
1009 }
1010
1011 declare void @__quantum__rt__initialize(i8*)
1012
1013 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1014
1015 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1016
1017 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1018
1019 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1020 attributes #1 = { "irreversible" }
1021
1022 ; module flags
1023
1024 !llvm.module.flags = !{!0, !1, !2, !3}
1025
1026 !0 = !{i32 1, !"qir_major_version", i32 1}
1027 !1 = !{i32 7, !"qir_minor_version", i32 0}
1028 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1029 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1030 "#]].assert_eq(&res);
1031 }
1032
1033 fn assert_qir_has_three_h_gates(qir: &str) {
1034 assert!(
1035 qir.contains("define i64 @ENTRYPOINT__main()"),
1036 "expected entry point in generated QIR, got:\n{qir}"
1037 );
1038 assert!(
1039 qir.contains(r#""required_num_qubits"="3""#),
1040 "expected three qubits in generated QIR, got:\n{qir}"
1041 );
1042 assert_eq!(
1043 qir.matches("call void @__quantum__qis__h__body").count(),
1044 3,
1045 "expected three H applications in generated QIR, got:\n{qir}"
1046 );
1047 }
1048
1049 fn user_global(interpreter: &Interpreter, name: &str) -> Value {
1050 interpreter
1051 .user_globals()
1052 .into_iter()
1053 .find_map(|(_, global_name, value)| (global_name.as_ref() == name).then_some(value))
1054 .unwrap_or_else(|| panic!("{name} should be present in user globals"))
1055 }
1056
1057 #[test]
1058 fn qirgen_does_not_corrupt_later_interpreter_eval_or_recompilation() {
1059 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1060 let (result, output) = line(
1061 &mut interpreter,
1062 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1063 );
1064 is_only_value(&result, &output, &Value::unit());
1065
1066 interpreter.qirgen("Foo()").expect("expected success");
1067
1068 let (result, output) = line(&mut interpreter, "Foo()");
1069 is_only_value(
1070 &result,
1071 &output,
1072 &Value::Result(qsc_eval::val::Result::Val(false)),
1073 );
1074
1075 let (result, output) = line(&mut interpreter, "operation Bar() : Result { Foo() }");
1076 is_only_value(&result, &output, &Value::unit());
1077 let (result, output) = line(&mut interpreter, "Bar()");
1078 is_only_value(
1079 &result,
1080 &output,
1081 &Value::Result(qsc_eval::val::Result::Val(false)),
1082 );
1083 }
1084
1085 #[test]
1086 fn qirgen_from_callable_user_global_succeeds_after_fresh_lowering() {
1087 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1088 let (result, output) = line(
1089 &mut interpreter,
1090 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1091 );
1092 is_only_value(&result, &output, &Value::unit());
1093
1094 let callable = user_global(&interpreter, "Foo");
1095
1096 let res = interpreter
1097 .qirgen_from_callable(&callable, Value::unit())
1098 .expect("expected success");
1099
1100 expect![[r#"
1101 %Result = type opaque
1102 %Qubit = type opaque
1103
1104 @0 = internal constant [4 x i8] c"0_r\00"
1105
1106 define i64 @ENTRYPOINT__main() #0 {
1107 block_0:
1108 call void @__quantum__rt__initialize(i8* null)
1109 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1110 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1111 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1112 ret i64 0
1113 }
1114
1115 declare void @__quantum__rt__initialize(i8*)
1116
1117 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1118
1119 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1120
1121 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1122
1123 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1124 attributes #1 = { "irreversible" }
1125
1126 ; module flags
1127
1128 !llvm.module.flags = !{!0, !1, !2, !3}
1129
1130 !0 = !{i32 1, !"qir_major_version", i32 1}
1131 !1 = !{i32 7, !"qir_minor_version", i32 0}
1132 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1133 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1134 "#]]
1135 .assert_eq(&res);
1136 }
1137
1138 #[test]
1139 fn qirgen_from_callable_with_global_callable_arg_succeeds() {
1140 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1141 let (result, output) = line(
1142 &mut interpreter,
1143 indoc! {r#"
1144 open Std.Canon;
1145
1146 operation InvokeWithQubits(nQubits : Int, f : Qubit[] => Unit) : Unit {
1147 use qs = Qubit[nQubits];
1148 f(qs);
1149 }
1150
1151 operation AllH(qs : Qubit[]) : Unit {
1152 struct Point3d { X : Double, Y : Double, Z : Double }
1153
1154 let point = new Point3d { X = 1.0, Y = 2.0, Z = 3.0 };
1155 let point2 = new Point3d { ...point, Z = 4.0 };
1156 let should_apply = point2.X == 1.0;
1157 if should_apply {
1158 ApplyToEach(H, qs);
1159 }
1160 }
1161
1162 operation UnusedIntOutput() : Int {
1163 1
1164 }
1165 "#},
1166 );
1167 is_only_value(&result, &output, &Value::unit());
1168
1169 let invoke_with_qubits = user_global(&interpreter, "InvokeWithQubits");
1170 let all_h = user_global(&interpreter, "AllH");
1171
1172 let qir = interpreter
1173 .qirgen_from_callable(
1174 &invoke_with_qubits,
1175 Value::Tuple(vec![Value::Int(3), all_h].into(), None),
1176 )
1177 .expect("expected success");
1178
1179 assert_qir_has_three_h_gates(&qir);
1180 }
1181
1182 #[test]
1183 fn qirgen_from_callable_with_closure_arg_succeeds() {
1184 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1185 let (result, output) = line(
1186 &mut interpreter,
1187 indoc! {r#"
1188 open Std.Canon;
1189
1190 operation InvokeWithQubits(nQubits : Int, f : Qubit[] => Unit) : Unit {
1191 use qs = Qubit[nQubits];
1192 f(qs);
1193 }
1194 "#},
1195 );
1196 is_only_value(&result, &output, &Value::unit());
1197
1198 let invoke_with_qubits = user_global(&interpreter, "InvokeWithQubits");
1199
1200 let (closure_result, closure_output) = line(&mut interpreter, "ApplyToEach(H, _)");
1201 assert!(
1202 closure_output.is_empty(),
1203 "unexpected output while creating closure: {closure_output}"
1204 );
1205 let apply_h = closure_result.expect("expected closure value");
1206
1207 let qir = interpreter
1208 .qirgen_from_callable(
1209 &invoke_with_qubits,
1210 Value::Tuple(vec![Value::Int(3), apply_h].into(), None),
1211 )
1212 .expect("expected success");
1213
1214 assert_qir_has_three_h_gates(&qir);
1215 }
1216
1217 #[test]
1218 fn qirgen_from_callable_with_arrow_input_reports_runtime_capability_errors() {
1219 let mut interpreter = get_interpreter_with_capabilities(
1220 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
1221 );
1222 let (result, output) = line(
1223 &mut interpreter,
1224 indoc! {r#"
1225 import Std.Convert.*;
1226
1227 operation InvokeWithMeasuredInt(f : (Int, Qubit) => Unit) : Unit {
1228 use q = Qubit();
1229 let i = if MResetZ(q) == One { 1 } else { 0 };
1230 f(i, q);
1231 }
1232
1233 operation RotateByInt(i : Int, q : Qubit) : Unit {
1234 Rx(IntAsDouble(i), q);
1235 }
1236 "#},
1237 );
1238 is_only_value(&result, &output, &Value::unit());
1239
1240 let invoke_with_measured_int = user_global(&interpreter, "InvokeWithMeasuredInt");
1241 let rotate_by_int = user_global(&interpreter, "RotateByInt");
1242
1243 let errors = interpreter
1244 .qirgen_from_callable(&invoke_with_measured_int, rotate_by_int)
1245 .expect_err("expected runtime capability error");
1246
1247 assert!(
1248 errors
1249 .iter()
1250 .all(|error| matches!(error, crate::interpret::Error::Pass(_))),
1251 "expected capability-check pass errors, got {errors:?}"
1252 );
1253 assert!(
1254 errors
1255 .iter()
1256 .any(|error| format!("{error:?}").contains("UseOfDynamicDouble")),
1257 "expected a dynamic double capability diagnostic, got {errors:?}"
1258 );
1259 }
1260
1261 #[test]
1262 fn qirgen_from_callable_profile_incompatible_outputs_report_callable_scoped_errors() {
1263 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1264 let (result, output) = line(
1265 &mut interpreter,
1266 indoc! {r#"
1267 operation ReturnInt() : Int {
1268 1
1269 }
1270
1271 operation ReturnDouble() : Double {
1272 1.0
1273 }
1274
1275 operation ReturnBool() : Bool {
1276 true
1277 }
1278
1279 operation ReturnString() : String {
1280 "hello"
1281 }
1282 "#},
1283 );
1284 is_only_value(&result, &output, &Value::unit());
1285
1286 let int_errors = interpreter
1287 .qirgen_from_callable(&user_global(&interpreter, "ReturnInt"), Value::unit())
1288 .expect_err("expected integer output rejection");
1289 is_error(
1290 &int_errors,
1291 &expect![[r#"
1292 cannot use an integer value as an output
1293 [line_0] [ReturnInt]
1294 "#]],
1295 );
1296
1297 let double_errors = interpreter
1298 .qirgen_from_callable(&user_global(&interpreter, "ReturnDouble"), Value::unit())
1299 .expect_err("expected double output rejection");
1300 is_error(
1301 &double_errors,
1302 &expect![[r#"
1303 cannot use a double value as an output
1304 [line_0] [ReturnDouble]
1305 "#]],
1306 );
1307
1308 let bool_errors = interpreter
1309 .qirgen_from_callable(&user_global(&interpreter, "ReturnBool"), Value::unit())
1310 .expect_err("expected bool output rejection");
1311 is_error(
1312 &bool_errors,
1313 &expect![[r#"
1314 cannot use a bool value as an output
1315 [line_0] [ReturnBool]
1316 "#]],
1317 );
1318
1319 let advanced_errors = interpreter
1320 .qirgen_from_callable(&user_global(&interpreter, "ReturnString"), Value::unit())
1321 .expect_err("expected advanced output rejection");
1322 is_error(
1323 &advanced_errors,
1324 &expect![[r#"
1325 cannot use value with advanced type as an output
1326 [line_0] [ReturnString]
1327 "#]],
1328 );
1329 }
1330
1331 #[test]
1332 fn qirgen_from_callable_does_not_corrupt_later_interpreter_eval_or_recompilation() {
1333 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1334 let (result, output) = line(
1335 &mut interpreter,
1336 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1337 );
1338 is_only_value(&result, &output, &Value::unit());
1339
1340 let callable = user_global(&interpreter, "Foo");
1341
1342 interpreter
1343 .qirgen_from_callable(&callable, Value::unit())
1344 .expect("expected success");
1345
1346 let mut cursor = Cursor::new(Vec::<u8>::new());
1347 let mut receiver = CursorReceiver::new(&mut cursor);
1348 let result = interpreter.invoke(&mut receiver, callable.clone(), Value::unit());
1349 let output = receiver.dump();
1350 is_only_value(
1351 &result,
1352 &output,
1353 &Value::Result(qsc_eval::val::Result::Val(false)),
1354 );
1355
1356 let (result, output) = line(&mut interpreter, "operation Bar() : Result { Foo() }");
1357 is_only_value(&result, &output, &Value::unit());
1358 let (result, output) = line(&mut interpreter, "Bar()");
1359 is_only_value(
1360 &result,
1361 &output,
1362 &Value::Result(qsc_eval::val::Result::Val(false)),
1363 );
1364 }
1365
1366 #[test]
1367 fn adaptive_qirgen() {
1368 let mut interpreter = get_interpreter_with_capabilities(
1369 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
1370 );
1371 let (result, output) = line(
1372 &mut interpreter,
1373 indoc! {r#"
1374 namespace Test {
1375 import Std.Math.*;
1376 open QIR.Intrinsic;
1377 @EntryPoint()
1378 operation Main() : Result {
1379 use q = Qubit();
1380 let pi_over_2 = 4.0 / 2.0;
1381 __quantum__qis__rz__body(pi_over_2, q);
1382 mutable some_angle = ArcSin(0.0);
1383 __quantum__qis__rz__body(some_angle, q);
1384 set some_angle = ArcCos(-1.0) / PI();
1385 __quantum__qis__rz__body(some_angle, q);
1386 __quantum__qis__mresetz__body(q)
1387 }
1388 }"#
1389 },
1390 );
1391 is_only_value(&result, &output, &Value::unit());
1392 let res = interpreter.qirgen("Test.Main()").expect("expected success");
1393 expect![[r#"
1394 %Result = type opaque
1395 %Qubit = type opaque
1396
1397 @0 = internal constant [4 x i8] c"0_r\00"
1398
1399 define i64 @ENTRYPOINT__main() #0 {
1400 block_0:
1401 call void @__quantum__rt__initialize(i8* null)
1402 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
1403 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
1404 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
1405 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1406 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1407 ret i64 0
1408 }
1409
1410 declare void @__quantum__rt__initialize(i8*)
1411
1412 declare void @__quantum__qis__rz__body(double, %Qubit*)
1413
1414 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1415
1416 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1417
1418 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
1419 attributes #1 = { "irreversible" }
1420
1421 ; module flags
1422
1423 !llvm.module.flags = !{!0, !1, !2, !3, !4}
1424
1425 !0 = !{i32 1, !"qir_major_version", i32 1}
1426 !1 = !{i32 7, !"qir_minor_version", i32 0}
1427 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1428 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1429 !4 = !{i32 5, !"int_computations", !{!"i64"}}
1430 "#]]
1431 .assert_eq(&res);
1432 }
1433
1434 #[test]
1435 fn base_get_rir() {
1436 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1437 let (result, output) = line(
1438 &mut interpreter,
1439 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1440 );
1441 is_only_value(&result, &output, &Value::unit());
1442 let res = interpreter.get_rir("Foo()").expect("expected success");
1443 // get_rir returns the raw RIR and the SSA-transformed RIR. The full
1444 // dump embeds source offsets in its debug metadata, so assert on the
1445 // stable structure rather than snapshotting the whole program.
1446 assert_eq!(res.len(), 2);
1447 let ssa = &res[1];
1448 assert!(ssa.contains("Program:"), "{ssa}");
1449 assert!(ssa.contains("capabilities: Base"), "{ssa}");
1450 assert!(ssa.contains("num_results: 1"), "{ssa}");
1451 assert!(ssa.contains("call_type: Measurement"), "{ssa}");
1452 }
1453
1454 #[test]
1455 fn adaptive_get_rir() {
1456 let mut interpreter = get_interpreter_with_capabilities(
1457 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
1458 );
1459 let (result, output) = line(
1460 &mut interpreter,
1461 indoc! {r#"
1462 namespace Test {
1463 import Std.Math.*;
1464 open QIR.Intrinsic;
1465 @EntryPoint()
1466 operation Main() : Result {
1467 use q = Qubit();
1468 let pi_over_2 = 4.0 / 2.0;
1469 __quantum__qis__rz__body(pi_over_2, q);
1470 __quantum__qis__mresetz__body(q)
1471 }
1472 }"#
1473 },
1474 );
1475 is_only_value(&result, &output, &Value::unit());
1476 let res = interpreter
1477 .get_rir("Test.Main()")
1478 .expect("expected success");
1479 assert_eq!(res.len(), 2);
1480 let ssa = &res[1];
1481 assert!(ssa.contains("Program:"), "{ssa}");
1482 assert!(ssa.contains("Adaptive"), "{ssa}");
1483 assert!(ssa.contains("num_results: 1"), "{ssa}");
1484 assert!(ssa.contains("call_type: Measurement"), "{ssa}");
1485 }
1486
1487 #[test]
1488 fn get_rir_fails_for_unrestricted_profile() {
1489 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::all());
1490 let (result, output) = line(
1491 &mut interpreter,
1492 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1493 );
1494 is_only_value(&result, &output, &Value::unit());
1495 let res = interpreter
1496 .get_rir("Foo()")
1497 .expect_err("expected get_rir to fail for the unrestricted profile");
1498 expect!["[UnsupportedRuntimeCapabilities]"].assert_eq(&format!("{res:?}"));
1499 }
1500
1501 #[test]
1502 fn adaptive_qirgen_source_entrypoint_uses_fresh_lowering() {
1503 let mut interpreter = get_interpreter_with_capabilities(
1504 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
1505 );
1506 let (result, output) = line(
1507 &mut interpreter,
1508 indoc! {r#"
1509 namespace Test {
1510 import Std.Intrinsic.*;
1511 import Std.Math.*;
1512 import Std.Measurement.*;
1513
1514 @EntryPoint()
1515 operation Main() : ((Result[], Int), Bool) {
1516 use registerA = Qubit[3];
1517 if true {
1518 X(registerA[0]);
1519 if true {
1520 X(registerA[1]);
1521 if false {
1522 X(registerA[2]);
1523 }
1524 }
1525 }
1526 let registerAMeasurements = MeasureEachZ(registerA);
1527
1528 mutable a = 0;
1529 if registerAMeasurements[0] == Zero {
1530 if registerAMeasurements[1] == Zero and registerAMeasurements[2] == Zero {
1531 set a = 0;
1532 } elif registerAMeasurements[1] == Zero and registerAMeasurements[2] == One {
1533 set a = 1;
1534 } elif registerAMeasurements[1] == One and registerAMeasurements[2] == Zero {
1535 set a = 2;
1536 } else {
1537 set a = 3;
1538 }
1539 } else {
1540 if registerAMeasurements[1] == Zero and registerAMeasurements[2] == Zero {
1541 set a = 4;
1542 } elif registerAMeasurements[1] == Zero and registerAMeasurements[2] == One {
1543 set a = 5;
1544 } elif registerAMeasurements[1] == One and registerAMeasurements[2] == Zero {
1545 set a = 6;
1546 } else {
1547 set a = 7;
1548 }
1549 }
1550 ResetAll(registerA);
1551
1552 use q = Qubit();
1553 ((registerAMeasurements, a), MResetZ(q) == One)
1554 }
1555 }"#
1556 },
1557 );
1558 is_only_value(&result, &output, &Value::unit());
1559
1560 let qir = interpreter.qirgen("Test.Main()").expect("expected success");
1561
1562 assert!(
1563 qir.contains("call void @__quantum__rt__int_record_output(i64 %var_"),
1564 "expected dynamic integer output to be recorded from an SSA value, got:\n{qir}"
1565 );
1566 assert!(
1567 !qir.contains("call void @__quantum__rt__int_record_output(i64 0,"),
1568 "expected source entrypoint QIR generation to avoid stale literal outputs, got:\n{qir}"
1569 );
1570 }
1571
1572 #[test]
1573 fn adaptive_qirgen_source_entrypoint_supports_measurement_comparisons() {
1574 let mut interpreter = get_interpreter_with_capabilities(
1575 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
1576 );
1577 let (result, output) = line(
1578 &mut interpreter,
1579 indoc! {r#"
1580 namespace Test {
1581 import Std.Intrinsic.*;
1582
1583 @EntryPoint()
1584 operation Main() : (Bool, Bool, Bool, Bool) {
1585 use (q0, q1) = (Qubit(), Qubit());
1586 X(q0);
1587 CNOT(q0, q1);
1588 let (r0, r1) = (M(q0), M(q1));
1589 Reset(q0);
1590 Reset(q1);
1591 return (r0 == One, r1 == Zero, r0 == r1, r0 == Zero ? false | true);
1592 }
1593 }"#
1594 },
1595 );
1596 is_only_value(&result, &output, &Value::unit());
1597
1598 let qir = interpreter.qirgen("Test.Main()").expect("expected success");
1599
1600 assert!(
1601 qir.contains(
1602 "call i1 @__quantum__rt__read_result(%Result* inttoptr (i64 0 to %Result*))"
1603 ),
1604 "expected measurement comparisons to lower through read_result, got:\n{qir}"
1605 );
1606 assert!(
1607 qir.contains("icmp eq i1 %var_5, %var_6"),
1608 "expected result-to-result equality to lower to an i1 comparison, got:\n{qir}"
1609 );
1610 }
1611
1612 #[test]
1613 fn adaptive_qirgen_nested_output_types() {
1614 let mut interpreter =
1615 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
1616 let (result, output) = line(
1617 &mut interpreter,
1618 indoc! {r#"
1619 namespace Test {
1620 open QIR.Intrinsic;
1621 @EntryPoint()
1622 operation Main() : (Result, (Bool, Bool)) {
1623 use q = Qubit();
1624 let r = __quantum__qis__mresetz__body(q);
1625 (r, (r == One, r == Zero))
1626 }
1627 }"#
1628 },
1629 );
1630 is_only_value(&result, &output, &Value::unit());
1631 let res = interpreter.qirgen("Test.Main()").expect("expected success");
1632 expect![[r#"
1633 %Result = type opaque
1634 %Qubit = type opaque
1635
1636 @0 = internal constant [4 x i8] c"0_t\00"
1637 @1 = internal constant [6 x i8] c"1_t0r\00"
1638 @2 = internal constant [6 x i8] c"2_t1t\00"
1639 @3 = internal constant [8 x i8] c"3_t1t0b\00"
1640 @4 = internal constant [8 x i8] c"4_t1t1b\00"
1641
1642 define i64 @ENTRYPOINT__main() #0 {
1643 block_0:
1644 call void @__quantum__rt__initialize(i8* null)
1645 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1646 %var_0 = call i1 @__quantum__rt__read_result(%Result* inttoptr (i64 0 to %Result*))
1647 %var_2 = call i1 @__quantum__rt__read_result(%Result* inttoptr (i64 0 to %Result*))
1648 %var_3 = icmp eq i1 %var_2, false
1649 call void @__quantum__rt__tuple_record_output(i64 2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1650 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
1651 call void @__quantum__rt__tuple_record_output(i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i64 0, i64 0))
1652 call void @__quantum__rt__bool_record_output(i1 %var_0, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @3, i64 0, i64 0))
1653 call void @__quantum__rt__bool_record_output(i1 %var_3, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @4, i64 0, i64 0))
1654 ret i64 0
1655 }
1656
1657 declare void @__quantum__rt__initialize(i8*)
1658
1659 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
1660
1661 declare i1 @__quantum__rt__read_result(%Result*)
1662
1663 declare void @__quantum__rt__tuple_record_output(i64, i8*)
1664
1665 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1666
1667 declare void @__quantum__rt__bool_record_output(i1, i8*)
1668
1669 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
1670 attributes #1 = { "irreversible" }
1671
1672 ; module flags
1673
1674 !llvm.module.flags = !{!0, !1, !2, !3}
1675
1676 !0 = !{i32 1, !"qir_major_version", i32 1}
1677 !1 = !{i32 7, !"qir_minor_version", i32 0}
1678 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1679 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1680 "#]]
1681 .assert_eq(&res);
1682 }
1683
1684 #[test]
1685 fn adaptive_qirgen_fails_when_entry_expr_does_not_match_profile() {
1686 let mut interpreter =
1687 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
1688 let (result, output) = line(
1689 &mut interpreter,
1690 indoc! {r#"
1691 use q = Qubit();
1692 mutable x = 1;
1693 "#
1694 },
1695 );
1696 is_only_value(&result, &output, &Value::unit());
1697 let res = interpreter
1698 .qirgen("if M(q) == One { set x = 2; }")
1699 .expect_err("expected error");
1700 is_error(
1701 &res,
1702 &expect![[r#"
1703 cannot use a dynamic integer value
1704 [<entry>] [set x = 2]
1705 "#]],
1706 );
1707 }
1708
1709 #[test]
1710 fn qirgen_entry_expr_in_block() {
1711 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1712 let (result, output) = line(
1713 &mut interpreter,
1714 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1715 );
1716 is_only_value(&result, &output, &Value::unit());
1717 let res = interpreter.qirgen("{Foo()}").expect("expected success");
1718 expect![[r#"
1719 %Result = type opaque
1720 %Qubit = type opaque
1721
1722 @0 = internal constant [4 x i8] c"0_r\00"
1723
1724 define i64 @ENTRYPOINT__main() #0 {
1725 block_0:
1726 call void @__quantum__rt__initialize(i8* null)
1727 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1728 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1729 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1730 ret i64 0
1731 }
1732
1733 declare void @__quantum__rt__initialize(i8*)
1734
1735 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1736
1737 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1738
1739 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1740
1741 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1742 attributes #1 = { "irreversible" }
1743
1744 ; module flags
1745
1746 !llvm.module.flags = !{!0, !1, !2, !3}
1747
1748 !0 = !{i32 1, !"qir_major_version", i32 1}
1749 !1 = !{i32 7, !"qir_minor_version", i32 0}
1750 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1751 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1752 "#]].assert_eq(&res);
1753 }
1754
1755 #[test]
1756 fn adaptive_rif_qirgen_entry_expr_apply_to_each_sx() {
1757 let mut interpreter = get_interpreter_with_capabilities(
1758 TargetCapabilityFlags::Adaptive
1759 | TargetCapabilityFlags::IntegerComputations
1760 | TargetCapabilityFlags::FloatingPointComputations,
1761 );
1762 let (result, output) = line(&mut interpreter, indoc! {"open Std.Canon;"});
1763 is_only_value(&result, &output, &Value::unit());
1764
1765 let res = interpreter
1766 .qirgen("{ use qs = Qubit[4]; ApplyToEach(SX, qs); }")
1767 .expect("expected success");
1768
1769 assert!(
1770 res.contains("declare void @__quantum__qis__sx__body(%Qubit*)"),
1771 "expected ApplyToEach(SX, qs) to generate SX calls, got:\n{res}"
1772 );
1773 }
1774
1775 #[test]
1776 fn qirgen_entry_expr_defines_operation() {
1777 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1778
1779 let (result, output) = line(
1780 &mut interpreter,
1781 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1782 );
1783 is_only_value(&result, &output, &Value::unit());
1784 let res = interpreter
1785 .qirgen("{operation Bar() : Unit {}; Foo()}")
1786 .expect("expected success");
1787 expect![[r#"
1788 %Result = type opaque
1789 %Qubit = type opaque
1790
1791 @0 = internal constant [4 x i8] c"0_r\00"
1792
1793 define i64 @ENTRYPOINT__main() #0 {
1794 block_0:
1795 call void @__quantum__rt__initialize(i8* null)
1796 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1797 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1798 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1799 ret i64 0
1800 }
1801
1802 declare void @__quantum__rt__initialize(i8*)
1803
1804 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1805
1806 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1807
1808 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1809
1810 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1811 attributes #1 = { "irreversible" }
1812
1813 ; module flags
1814
1815 !llvm.module.flags = !{!0, !1, !2, !3}
1816
1817 !0 = !{i32 1, !"qir_major_version", i32 1}
1818 !1 = !{i32 7, !"qir_minor_version", i32 0}
1819 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1820 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1821 "#]].assert_eq(&res);
1822
1823 // Operation should not be visible from global scope
1824 let (result, output) = line(&mut interpreter, indoc! {"Bar()"});
1825 is_only_error(
1826 &result,
1827 &output,
1828 &expect![[r#"
1829 name error: `Bar` not found
1830 [line_1] [Bar]
1831 "#]],
1832 );
1833 }
1834
1835 #[test]
1836 fn qirgen_multiple_exprs_parse_fail() {
1837 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1838 let (result, output) = line(
1839 &mut interpreter,
1840 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1841 );
1842 is_only_value(&result, &output, &Value::unit());
1843 let res = interpreter
1844 .qirgen("Foo(); operation Bar() : Unit {}; Foo()")
1845 .expect_err("expected error");
1846 is_error(
1847 &res,
1848 &expect![[r#"
1849 syntax error: expected EOF, found `;`
1850 [<entry>] [;]
1851 "#]],
1852 );
1853 }
1854
1855 #[test]
1856 fn qirgen_entry_expr_defines_operation_then_more_operations() {
1857 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1858 let (result, output) = line(
1859 &mut interpreter,
1860 indoc! {"operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1861 );
1862 is_only_value(&result, &output, &Value::unit());
1863 let res = interpreter
1864 .qirgen("{operation Bar() : Unit {}; Foo()}")
1865 .expect("expected success");
1866 expect![[r#"
1867 %Result = type opaque
1868 %Qubit = type opaque
1869
1870 @0 = internal constant [4 x i8] c"0_r\00"
1871
1872 define i64 @ENTRYPOINT__main() #0 {
1873 block_0:
1874 call void @__quantum__rt__initialize(i8* null)
1875 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1876 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1877 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1878 ret i64 0
1879 }
1880
1881 declare void @__quantum__rt__initialize(i8*)
1882
1883 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1884
1885 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1886
1887 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1888
1889 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1890 attributes #1 = { "irreversible" }
1891
1892 ; module flags
1893
1894 !llvm.module.flags = !{!0, !1, !2, !3}
1895
1896 !0 = !{i32 1, !"qir_major_version", i32 1}
1897 !1 = !{i32 7, !"qir_minor_version", i32 0}
1898 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1899 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1900 "#]].assert_eq(&res);
1901
1902 let (result, output) = line(
1903 &mut interpreter,
1904 indoc! {"operation Baz() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; } "},
1905 );
1906 is_only_value(&result, &output, &Value::unit());
1907
1908 let (result, output) = line(&mut interpreter, indoc! {"Bar()"});
1909 is_only_error(
1910 &result,
1911 &output,
1912 &expect![[r#"
1913 name error: `Bar` not found
1914 [line_2] [Bar]
1915 "#]],
1916 );
1917 }
1918
1919 #[test]
1920 fn qirgen_define_operation_use_it() {
1921 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1922 let res = interpreter
1923 .qirgen("{ operation Foo() : Result { use q = Qubit(); let r = M(q); Reset(q); return r; }; Foo() }")
1924 .expect("expected success");
1925 expect![[r#"
1926 %Result = type opaque
1927 %Qubit = type opaque
1928
1929 @0 = internal constant [4 x i8] c"0_r\00"
1930
1931 define i64 @ENTRYPOINT__main() #0 {
1932 block_0:
1933 call void @__quantum__rt__initialize(i8* null)
1934 call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1935 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1936 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1937 ret i64 0
1938 }
1939
1940 declare void @__quantum__rt__initialize(i8*)
1941
1942 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1943
1944 declare void @__quantum__rt__result_record_output(%Result*, i8*)
1945
1946 declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
1947
1948 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
1949 attributes #1 = { "irreversible" }
1950
1951 ; module flags
1952
1953 !llvm.module.flags = !{!0, !1, !2, !3}
1954
1955 !0 = !{i32 1, !"qir_major_version", i32 1}
1956 !1 = !{i32 7, !"qir_minor_version", i32 0}
1957 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
1958 !3 = !{i32 1, !"dynamic_result_management", i1 false}
1959 "#]].assert_eq(&res);
1960 }
1961
1962 #[test]
1963 fn qirgen_entry_expr_profile_incompatible() {
1964 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
1965 let res = interpreter
1966 .qirgen("1")
1967 .expect_err("expected qirgen to fail");
1968 is_error(
1969 &res,
1970 &expect![[r#"
1971 cannot use an integer value as an output
1972 [<entry>] [1]
1973 "#]],
1974 );
1975 }
1976
1977 #[test]
1978 fn adaptive_qirgen_custom_intrinsic_returning_bool() {
1979 let mut interpreter =
1980 get_interpreter_with_capabilities(TargetCapabilityFlags::Adaptive);
1981 let res = interpreter
1982 .qirgen("{ operation check_result(r : Result) : Bool { body intrinsic; }; operation Foo() : Bool { use q = Qubit(); let r = MResetZ(q); check_result(r) } Foo() }")
1983 .expect("expected success");
1984 expect![[r#"
1985 %Result = type opaque
1986 %Qubit = type opaque
1987
1988 @0 = internal constant [4 x i8] c"0_b\00"
1989
1990 define i64 @ENTRYPOINT__main() #0 {
1991 block_0:
1992 call void @__quantum__rt__initialize(i8* null)
1993 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1994 %var_0 = call i1 @check_result(%Result* inttoptr (i64 0 to %Result*))
1995 call void @__quantum__rt__bool_record_output(i1 %var_0, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i64 0, i64 0))
1996 ret i64 0
1997 }
1998
1999 declare void @__quantum__rt__initialize(i8*)
2000
2001 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
2002
2003 declare i1 @check_result(%Result*)
2004
2005 declare void @__quantum__rt__bool_record_output(i1, i8*)
2006
2007 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
2008 attributes #1 = { "irreversible" }
2009
2010 ; module flags
2011
2012 !llvm.module.flags = !{!0, !1, !2, !3}
2013
2014 !0 = !{i32 1, !"qir_major_version", i32 1}
2015 !1 = !{i32 7, !"qir_minor_version", i32 0}
2016 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
2017 !3 = !{i32 1, !"dynamic_result_management", i1 false}
2018 "#]].assert_eq(&res);
2019 }
2020
2021 #[test]
2022 fn run_with_shots() {
2023 let mut interpreter = get_interpreter();
2024 let (result, output) = line(
2025 &mut interpreter,
2026 "operation Foo(qs : Qubit[]) : Unit { Microsoft.Quantum.Diagnostics.DumpMachine(); }",
2027 );
2028 is_only_value(&result, &output, &Value::unit());
2029 for _ in 0..4 {
2030 let (results, output) = run(&mut interpreter, "{use qs = Qubit[2]; Foo(qs)}");
2031 is_unit_with_output(&results, &output, "STATE:\n|00⟩: 1+0i");
2032 }
2033 }
2034
2035 #[test]
2036 fn run_parse_error() {
2037 let mut interpreter = get_interpreter();
2038 let (results, _) = run(&mut interpreter, "Foo)");
2039 results.expect_err("run() should fail");
2040 }
2041
2042 #[test]
2043 fn run_compile_error() {
2044 let mut interpreter = get_interpreter();
2045 let (results, _) = run(&mut interpreter, "Foo()");
2046 results.expect_err("run() should fail");
2047 }
2048
2049 #[test]
2050 fn run_multiple_statements_with_return_value() {
2051 let mut interpreter = get_interpreter();
2052 let (result, output) = line(&mut interpreter, "operation Foo() : Int { 1 }");
2053 is_only_value(&result, &output, &Value::unit());
2054 let (result, output) = line(&mut interpreter, "operation Bar() : Int { 2 }");
2055 is_only_value(&result, &output, &Value::unit());
2056 let (result, output) = run(&mut interpreter, "{ Foo(); Bar() }");
2057 is_only_value(&result, &output, &Value::Int(2));
2058 }
2059
2060 #[test]
2061 fn run_runtime_failure() {
2062 let mut interpreter = get_interpreter();
2063 let (result, output) = line(
2064 &mut interpreter,
2065 r#"operation Foo() : Int { fail "failed" }"#,
2066 );
2067 is_only_value(&result, &output, &Value::unit());
2068 for _ in 0..1 {
2069 let (result, output) = run(&mut interpreter, "Foo()");
2070 is_only_error(
2071 &result,
2072 &output,
2073 &expect![[r#"
2074 runtime error: program failed: failed
2075 explicit fail [line_0] [fail "failed"]
2076 "#]],
2077 );
2078 }
2079 }
2080
2081 #[test]
2082 fn run_output_merged() {
2083 let mut interpreter = get_interpreter();
2084 let (result, output) = line(
2085 &mut interpreter,
2086 r#"operation Foo() : Unit { Message("hello!") }"#,
2087 );
2088 is_only_value(&result, &output, &Value::unit());
2089 for _ in 0..4 {
2090 let (result, output) = run(&mut interpreter, "Foo()");
2091 is_unit_with_output(&result, &output, "hello!");
2092 }
2093 }
2094
2095 #[test]
2096 fn base_prof_non_result_return() {
2097 let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
2098 let (result, output) = line(&mut interpreter, "123");
2099 is_only_value(&result, &output, &Value::Int(123));
2100 }
2101 }
2102
2103 fn get_interpreter() -> Interpreter {
2104 let (std_id, store) =
2105 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2106 let dependencies = &[(std_id, None)];
2107 Interpreter::new(
2108 SourceMap::default(),
2109 PackageType::Lib,
2110 TargetCapabilityFlags::all(),
2111 LanguageFeatures::default(),
2112 store,
2113 dependencies,
2114 )
2115 .expect("interpreter should be created")
2116 }
2117
2118 fn get_interpreter_with_capabilities(capabilities: TargetCapabilityFlags) -> Interpreter {
2119 let (std_id, store) = crate::compile::package_store_with_stdlib(capabilities);
2120 let dependencies = &[(std_id, None)];
2121 Interpreter::new(
2122 SourceMap::default(),
2123 PackageType::Lib,
2124 capabilities,
2125 LanguageFeatures::default(),
2126 store,
2127 dependencies,
2128 )
2129 .expect("interpreter should be created")
2130 }
2131
2132 fn is_only_value(result: &InterpretResult, output: &str, value: &Value) {
2133 assert_eq!("", output);
2134
2135 match result {
2136 Ok(v) => assert_eq!(value, v),
2137 Err(e) => panic!("Expected {value:?}, got {e:?}"),
2138 }
2139 }
2140
2141 fn is_unit_with_output_eval_entry(
2142 result: &InterpretResult,
2143 output: &str,
2144 expected_output: &str,
2145 ) {
2146 assert_eq!(expected_output, output);
2147
2148 match result {
2149 Ok(value) => assert_eq!(Value::unit(), *value),
2150 Err(e) => panic!("Expected unit value, got {e:?}"),
2151 }
2152 }
2153
2154 fn is_unit_with_output(result: &InterpretResult, output: &str, expected_output: &str) {
2155 match result {
2156 Ok(value) => assert_eq!(Value::unit(), *value),
2157 Err(e) => panic!("Expected unit value, got {e:?}"),
2158 }
2159 assert_eq!(expected_output, output);
2160 }
2161
2162 fn is_only_error<E>(result: &Result<Value, Vec<E>>, output: &str, expected_errors: &Expect)
2163 where
2164 E: Diagnostic,
2165 {
2166 assert_eq!("", output);
2167
2168 match result {
2169 Ok(value) => panic!("Expected error , got {value:?}"),
2170 Err(errors) => is_error(errors, expected_errors),
2171 }
2172 }
2173
2174 fn is_error<E>(errors: &Vec<E>, expected_errors: &Expect)
2175 where
2176 E: Diagnostic,
2177 {
2178 let mut actual = String::new();
2179 for error in errors {
2180 write!(actual, "{error}").expect("writing should succeed");
2181 for s in iter::successors(error.source(), |&s| s.source()) {
2182 write!(actual, ": {s}").expect("writing should succeed");
2183 }
2184 for label in error.labels().into_iter().flatten() {
2185 let span = error
2186 .source_code()
2187 .expect("expected valid source code")
2188 .read_span(label.inner(), 0, 0)
2189 .expect("expected to be able to read span");
2190
2191 write!(
2192 actual,
2193 "\n {} [{}] [{}]",
2194 label.label().unwrap_or(""),
2195 span.name().expect("expected source file name"),
2196 from_utf8(span.data()).expect("expected valid utf-8 string"),
2197 )
2198 .expect("writing should succeed");
2199 }
2200 writeln!(actual).expect("writing should succeed");
2201 }
2202
2203 expected_errors.assert_eq(&actual);
2204 }
2205
2206 #[cfg(test)]
2207 mod with_sources {
2208 use std::{sync::Arc, vec};
2209
2210 use super::*;
2211 use crate::interpret::Debugger;
2212 use crate::line_column::Encoding;
2213 use expect_test::expect;
2214 use indoc::indoc;
2215
2216 use qsc_ast::ast::{
2217 Expr, ExprKind, NodeId, Package, Path, PathKind, Stmt, StmtKind, TopLevelNode,
2218 };
2219 use qsc_data_structures::source::SourceMap;
2220 use qsc_data_structures::span::Span;
2221 use qsc_passes::PackageType;
2222
2223 #[test]
2224 fn entry_expr_is_executed() {
2225 let source = indoc! { r#"
2226 namespace Test {
2227 @EntryPoint()
2228 operation Main() : Unit {
2229 Message("hello there...")
2230 }
2231 }"#};
2232
2233 let sources = SourceMap::new([("test".into(), source.into())], None);
2234 let (std_id, store) =
2235 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2236 let mut interpreter = Interpreter::new(
2237 sources,
2238 PackageType::Exe,
2239 TargetCapabilityFlags::all(),
2240 LanguageFeatures::default(),
2241 store,
2242 &[(std_id, None)],
2243 )
2244 .expect("interpreter should be created");
2245
2246 let (result, output) = entry(&mut interpreter);
2247 is_unit_with_output_eval_entry(&result, &output, "hello there...");
2248 }
2249
2250 #[test]
2251 fn invalid_partial_application_should_fail_not_panic() {
2252 // Found via fuzzing, see #2363
2253 let source = "operation e(oracle:(w=>)){oracle=i(_)";
2254 let sources = SourceMap::new([("test".into(), source.into())], None);
2255 let (std_id, store) =
2256 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2257 assert!(
2258 Interpreter::new(
2259 sources,
2260 PackageType::Exe,
2261 TargetCapabilityFlags::all(),
2262 LanguageFeatures::default(),
2263 store,
2264 &[(std_id, None)],
2265 )
2266 .is_err(),
2267 "interpreter should fail with error"
2268 );
2269 }
2270
2271 #[test]
2272 fn errors_returned_if_sources_do_not_match_profile() {
2273 let source = indoc! { r#"
2274 namespace A { operation Test() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x } }"#};
2275
2276 let sources = SourceMap::new([("test".into(), source.into())], Some("A.Test()".into()));
2277 let (std_id, store) =
2278 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2279 let result = Interpreter::new(
2280 sources,
2281 PackageType::Exe,
2282 TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations,
2283 LanguageFeatures::default(),
2284 store,
2285 &[(std_id, None)],
2286 );
2287
2288 match result {
2289 Ok(_) => panic!("Expected error, got interpreter."),
2290 Err(errors) => is_error(
2291 &errors,
2292 &expect![[r#"
2293 cannot use a dynamic double value
2294 [<entry>] [A.Test()]
2295 cannot use a double value as an output
2296 [<entry>] [A.Test()]
2297 cannot use a dynamic double value
2298 [test] [set x = 2.0]
2299 cannot use a dynamic double value
2300 [test] [x]
2301 "#]],
2302 ),
2303 }
2304 }
2305
2306 #[test]
2307 fn stdlib_members_can_be_accessed_from_sources() {
2308 let source = indoc! { r#"
2309 namespace Test {
2310 operation Main() : Unit {
2311 Message("hello there...")
2312 }
2313 }"#};
2314
2315 let sources = SourceMap::new([("test".into(), source.into())], None);
2316 let (std_id, store) =
2317 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2318 let dependencies = &[(std_id, None)];
2319 let mut interpreter = Interpreter::new(
2320 sources,
2321 PackageType::Lib,
2322 TargetCapabilityFlags::all(),
2323 LanguageFeatures::default(),
2324 store,
2325 dependencies,
2326 )
2327 .expect("interpreter should be created");
2328
2329 let (result, output) = line(&mut interpreter, "Test.Main()");
2330 is_unit_with_output(&result, &output, "hello there...");
2331 }
2332
2333 #[test]
2334 fn members_from_namespaced_sources_are_in_context() {
2335 let source = indoc! { r#"
2336 namespace Test {
2337 function Hello() : String {
2338 "hello there..."
2339 }
2340
2341 operation Main() : String {
2342 Hello()
2343 }
2344 }"#};
2345
2346 let sources = SourceMap::new([("test".into(), source.into())], None);
2347 let store = crate::PackageStore::new(crate::compile::core());
2348 let mut interpreter = Interpreter::new(
2349 sources,
2350 PackageType::Lib,
2351 TargetCapabilityFlags::all(),
2352 LanguageFeatures::default(),
2353 store,
2354 &[],
2355 )
2356 .expect("interpreter should be created");
2357
2358 let (result, output) = line(&mut interpreter, "Test.Hello()");
2359 is_only_value(&result, &output, &Value::String("hello there...".into()));
2360 let (result, output) = line(&mut interpreter, "Test.Main()");
2361 is_only_value(&result, &output, &Value::String("hello there...".into()));
2362 }
2363
2364 #[test]
2365 fn multiple_files_are_loaded_from_sources_into_eval_context() {
2366 let sources: [(Arc<str>, Arc<str>); 2] = [
2367 (
2368 "a.qs".into(),
2369 r#"
2370 namespace Test {
2371 function Hello() : String {
2372 "hello there..."
2373 }
2374 }"#
2375 .into(),
2376 ),
2377 (
2378 "b.qs".into(),
2379 r#"
2380 namespace Test2 {
2381 open Test;
2382 @EntryPoint()
2383 operation Main() : String {
2384 Hello();
2385 Hello()
2386 }
2387 }"#
2388 .into(),
2389 ),
2390 ];
2391
2392 let sources = SourceMap::new(sources, None);
2393 let store = crate::PackageStore::new(crate::compile::core());
2394 let debugger = Debugger::new(
2395 sources,
2396 TargetCapabilityFlags::all(),
2397 Encoding::Utf8,
2398 LanguageFeatures::default(),
2399 store,
2400 &[],
2401 )
2402 .expect("debugger should be created");
2403 let bps = debugger.get_breakpoints("a.qs");
2404 assert_eq!(1, bps.len());
2405 let bps = debugger.get_breakpoints("b.qs");
2406 assert_eq!(2, bps.len());
2407 }
2408
2409 #[test]
2410 fn debugger_simple_execution_succeeds() {
2411 let source = indoc! { r#"
2412 namespace Test {
2413 function Hello() : Unit {
2414 Message("hello there...");
2415 }
2416
2417 @EntryPoint()
2418 operation Main() : Unit {
2419 Hello()
2420 }
2421 }"#};
2422
2423 let sources = SourceMap::new([("test".into(), source.into())], None);
2424 let (std_id, store) =
2425 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2426 let mut debugger = Debugger::new(
2427 sources,
2428 TargetCapabilityFlags::all(),
2429 Encoding::Utf8,
2430 LanguageFeatures::default(),
2431 store,
2432 &[(std_id, None)],
2433 )
2434 .expect("debugger should be created");
2435 let (result, output) = entry(&mut debugger.interpreter);
2436 is_unit_with_output_eval_entry(&result, &output, "hello there...");
2437 }
2438
2439 #[test]
2440 fn debugger_execution_with_call_to_library_succeeds() {
2441 let source = indoc! { r#"
2442 namespace Test {
2443 import Std.Math.*;
2444 @EntryPoint()
2445 operation Main() : Int {
2446 Binom(31, 7)
2447 }
2448 }"#};
2449
2450 let sources = SourceMap::new([("test".into(), source.into())], None);
2451 let (std_id, store) =
2452 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2453 let mut debugger = Debugger::new(
2454 sources,
2455 TargetCapabilityFlags::all(),
2456 Encoding::Utf8,
2457 LanguageFeatures::default(),
2458 store,
2459 &[(std_id, None)],
2460 )
2461 .expect("debugger should be created");
2462 let (result, output) = entry(&mut debugger.interpreter);
2463 is_only_value(&result, &output, &Value::Int(2_629_575));
2464 }
2465
2466 #[test]
2467 fn debugger_execution_with_early_return_succeeds() {
2468 let source = indoc! { r#"
2469 namespace Test {
2470 import Std.Arrays.*;
2471
2472 operation Max20(i : Int) : Int {
2473 if (i > 20) {
2474 return 20;
2475 }
2476 return i;
2477 }
2478
2479 @EntryPoint()
2480 operation Main() : Int[] {
2481 ForEach(Max20, [10, 20, 30, 40, 50])
2482 }
2483 }"#};
2484
2485 let sources = SourceMap::new([("test".into(), source.into())], None);
2486 let (std_id, store) =
2487 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2488 let mut debugger = Debugger::new(
2489 sources,
2490 TargetCapabilityFlags::all(),
2491 Encoding::Utf8,
2492 LanguageFeatures::default(),
2493 store,
2494 &[(std_id, None)],
2495 )
2496 .expect("debugger should be created");
2497
2498 let (result, output) = entry(&mut debugger.interpreter);
2499 is_only_value(
2500 &result,
2501 &output,
2502 &Value::Array(
2503 vec![
2504 Value::Int(10),
2505 Value::Int(20),
2506 Value::Int(20),
2507 Value::Int(20),
2508 Value::Int(20),
2509 ]
2510 .into(),
2511 ),
2512 );
2513 }
2514
2515 #[test]
2516 fn multiple_namespaces_are_loaded_from_sources_into_eval_context() {
2517 let source = indoc! { r#"
2518 namespace Test {
2519 function Hello() : String {
2520 "hello there..."
2521 }
2522 }
2523 namespace Test2 {
2524 open Test;
2525 operation Main() : String {
2526 Hello()
2527 }
2528 }"#};
2529
2530 let sources = SourceMap::new([("test".into(), source.into())], None);
2531 let store = crate::PackageStore::new(crate::compile::core());
2532 let mut interpreter = Interpreter::new(
2533 sources,
2534 PackageType::Lib,
2535 TargetCapabilityFlags::all(),
2536 LanguageFeatures::default(),
2537 store,
2538 &[],
2539 )
2540 .expect("interpreter should be created");
2541 let (result, output) = line(&mut interpreter, "Test.Hello()");
2542 is_only_value(&result, &output, &Value::String("hello there...".into()));
2543 let (result, output) = line(&mut interpreter, "Test2.Main()");
2544 is_only_value(&result, &output, &Value::String("hello there...".into()));
2545 }
2546
2547 #[test]
2548 fn runtime_error_from_stdlib() {
2549 let sources = SourceMap::new(
2550 [(
2551 "test".into(),
2552 "namespace Foo {
2553 operation Bar(): Unit {
2554 let x = -1;
2555 use qs = Qubit[x];
2556 }
2557 }
2558 "
2559 .into(),
2560 )],
2561 Some("Foo.Bar()".into()),
2562 );
2563
2564 let store = crate::PackageStore::new(crate::compile::core());
2565 let mut interpreter = Interpreter::new(
2566 sources,
2567 PackageType::Lib,
2568 TargetCapabilityFlags::all(),
2569 LanguageFeatures::default(),
2570 store,
2571 &[],
2572 )
2573 .expect("interpreter should be created");
2574
2575 let (result, output) = entry(&mut interpreter);
2576 is_only_error(
2577 &result,
2578 &output,
2579 &expect![[r#"
2580 runtime error: program failed: Cannot allocate qubit array with a negative length
2581 explicit fail [qsharp-library-source:core/qir.qs] [fail "Cannot allocate qubit array with a negative length"]
2582 "#]],
2583 );
2584 }
2585
2586 #[test]
2587 fn interpreter_returns_items_from_source() {
2588 let sources = SourceMap::new(
2589 [(
2590 "test".into(),
2591 "namespace A {
2592 operation B(): Unit { }
2593 }
2594 "
2595 .into(),
2596 )],
2597 Some("A.B()".into()),
2598 );
2599
2600 let (std_id, store) =
2601 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2602 let interpreter = Interpreter::new(
2603 sources,
2604 PackageType::Lib,
2605 TargetCapabilityFlags::all(),
2606 LanguageFeatures::default(),
2607 store,
2608 &[(std_id, None)],
2609 )
2610 .expect("interpreter should be created");
2611
2612 let items = interpreter.source_globals();
2613 assert_eq!(1, items.len());
2614 expect![[r#"
2615 [
2616 "A",
2617 ]
2618 "#]]
2619 .assert_debug_eq(&items[0].0);
2620 expect![[r#"
2621 "B"
2622 "#]]
2623 .assert_debug_eq(&items[0].1);
2624 }
2625
2626 #[test]
2627 fn interpreter_can_be_created_from_ast() {
2628 let sources = SourceMap::new(
2629 [(
2630 "test".into(),
2631 "namespace A {
2632 operation B(): Result {
2633 use qs = Qubit[2];
2634 X(qs[0]);
2635 CNOT(qs[0], qs[1]);
2636 let res = Measure([PauliZ, PauliZ], qs[...1]);
2637 ResetAll(qs);
2638 res
2639 }
2640 }
2641 "
2642 .into(),
2643 )],
2644 Some("A.B()".into()),
2645 );
2646
2647 let (package_type, capabilities, language_features) = (
2648 PackageType::Lib,
2649 TargetCapabilityFlags::all(),
2650 LanguageFeatures::default(),
2651 );
2652
2653 let mut store = crate::PackageStore::new(crate::compile::core());
2654 let dependencies = vec![(
2655 store.insert(crate::compile::std(&store, capabilities)),
2656 None,
2657 )];
2658
2659 let (mut unit, errors) = crate::compile::compile(
2660 &store,
2661 &dependencies,
2662 sources,
2663 package_type,
2664 capabilities,
2665 language_features,
2666 );
2667 unit.expose();
2668 for e in &errors {
2669 eprintln!("{e:?}");
2670 }
2671 assert!(errors.is_empty(), "compilation failed: {}", errors[0]);
2672 let package_id = store.insert(unit);
2673
2674 let mut interpreter = Interpreter::with_package_store(
2675 false,
2676 store,
2677 package_id,
2678 capabilities,
2679 language_features,
2680 &dependencies,
2681 )
2682 .expect("interpreter should be created");
2683 let (result, output) = entry(&mut interpreter);
2684 is_only_value(
2685 &result,
2686 &output,
2687 &Value::Result(qsc_eval::val::Result::Val(false)),
2688 );
2689 }
2690
2691 #[test]
2692 fn ast_fragments_can_be_evaluated() {
2693 let sources = SourceMap::new(
2694 [(
2695 "test".into(),
2696 "namespace A {
2697 operation B(): Result {
2698 use qs = Qubit[2];
2699 X(qs[0]);
2700 CNOT(qs[0], qs[1]);
2701 let res = Measure([PauliZ, PauliZ], qs[...1]);
2702 ResetAll(qs);
2703 res
2704 }
2705 }
2706 "
2707 .into(),
2708 )],
2709 None,
2710 );
2711 let (std_id, store) =
2712 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2713 let mut interpreter = Interpreter::new(
2714 sources,
2715 PackageType::Lib,
2716 TargetCapabilityFlags::all(),
2717 LanguageFeatures::default(),
2718 store,
2719 &[(std_id, None)],
2720 )
2721 .expect("interpreter should be created");
2722
2723 let package = get_package_for_call("A", "B");
2724 let (result, output) = fragment(&mut interpreter, "A.B()", package);
2725 is_only_value(
2726 &result,
2727 &output,
2728 &Value::Result(qsc_eval::val::Result::Val(false)),
2729 );
2730 }
2731
2732 #[test]
2733 fn ast_fragments_evaluation_returns_runtime_errors() {
2734 let sources = SourceMap::new(
2735 [(
2736 "test".into(),
2737 "namespace A {
2738 operation B(): Int {
2739 42 / 0
2740 }
2741 }
2742 "
2743 .into(),
2744 )],
2745 None,
2746 );
2747 let (std_id, store) =
2748 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2749 let mut interpreter = Interpreter::new(
2750 sources,
2751 PackageType::Lib,
2752 TargetCapabilityFlags::all(),
2753 LanguageFeatures::default(),
2754 store,
2755 &[(std_id, None)],
2756 )
2757 .expect("interpreter should be created");
2758
2759 let package = get_package_for_call("A", "B");
2760 let (result, output) = fragment(&mut interpreter, "A.B()", package);
2761 is_only_error(
2762 &result,
2763 &output,
2764 &expect![[r#"
2765 runtime error: division by zero
2766 cannot divide by zero [test] [0]
2767 "#]],
2768 );
2769 }
2770
2771 fn get_package_for_call(ns: &str, name: &str) -> crate::ast::Package {
2772 let args = Expr {
2773 id: NodeId::default(),
2774 span: Span::default(),
2775 kind: Box::new(ExprKind::Tuple(Box::new([]))),
2776 };
2777 let path = Path {
2778 id: NodeId::default(),
2779 span: Span::default(),
2780 segments: Some(
2781 std::iter::once(qsc_ast::ast::Ident {
2782 id: NodeId::default(),
2783 span: Span::default(),
2784 name: ns.into(),
2785 })
2786 .collect(),
2787 ),
2788 name: Box::new(qsc_ast::ast::Ident {
2789 id: NodeId::default(),
2790 span: Span::default(),
2791 name: name.into(),
2792 }),
2793 };
2794 let path_expr = Expr {
2795 id: NodeId::default(),
2796 span: Span::default(),
2797 kind: Box::new(ExprKind::Path(PathKind::Ok(Box::new(path)))),
2798 };
2799 let expr = Expr {
2800 id: NodeId::default(),
2801 span: Span::default(),
2802 kind: Box::new(ExprKind::Call(Box::new(path_expr), Box::new(args))),
2803 };
2804 let stmt = Stmt {
2805 id: NodeId::default(),
2806 span: Span::default(),
2807 kind: Box::new(StmtKind::Expr(Box::new(expr))),
2808 };
2809 let top_level = TopLevelNode::Stmt(Box::new(stmt));
2810 Package {
2811 id: NodeId::default(),
2812 nodes: vec![top_level].into_boxed_slice(),
2813 entry: None,
2814 }
2815 }
2816
2817 #[test]
2818 fn name_resolution_from_source_named_main_should_succeed() {
2819 let sources = SourceMap::new(
2820 [(
2821 "Main".into(),
2822 r#"function Foo() : Unit { Message("hello there..."); }"#.into(),
2823 )],
2824 None,
2825 );
2826 let (std_id, store) =
2827 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2828 let mut interpreter = Interpreter::new(
2829 sources,
2830 PackageType::Lib,
2831 TargetCapabilityFlags::all(),
2832 LanguageFeatures::default(),
2833 store,
2834 &[(std_id, None)],
2835 )
2836 .expect("interpreter should be created");
2837
2838 // Operations defined in Main.qs should also be visible with Main qualifier.
2839 let (result, output) = line(&mut interpreter, "Main.Foo()");
2840 is_unit_with_output(&result, &output, "hello there...");
2841
2842 // Operations defined in Main.qs should be importable with fully qualified name.
2843 let (result, output) = line(&mut interpreter, "import Main.Foo;");
2844 is_only_value(&result, &output, &Value::unit());
2845
2846 // After import the operation can be invoked without Main qualifier.
2847 let (result, output) = line(&mut interpreter, "Foo()");
2848 is_unit_with_output(&result, &output, "hello there...");
2849 }
2850
2851 #[test]
2852 fn name_resolution_from_source_named_main_without_full_path_or_import_should_fail() {
2853 let sources = SourceMap::new(
2854 [(
2855 "Main".into(),
2856 r#"function Foo() : Unit { Message("hello there..."); }"#.into(),
2857 )],
2858 None,
2859 );
2860 let (std_id, store) =
2861 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2862 let mut interpreter = Interpreter::new(
2863 sources,
2864 PackageType::Lib,
2865 TargetCapabilityFlags::all(),
2866 LanguageFeatures::default(),
2867 store,
2868 &[(std_id, None)],
2869 )
2870 .expect("interpreter should be created");
2871
2872 // Operations defined in Main.qs should also be visible with Main qualifier.
2873 let (errors, _) = line(&mut interpreter, "Foo()");
2874 is_error(
2875 &errors.expect_err("line invocation should fail with error"),
2876 &expect![[r#"
2877 name error: `Foo` not found
2878 [line_0] [Foo]
2879 "#]],
2880 );
2881 }
2882
2883 /// Found via fuzzing, see #2426 <https://github.com/microsoft/qdk/issues/2426>
2884 #[test]
2885 fn recursive_type_constraint_should_fail() {
2886 let sources = SourceMap::new(
2887 [(
2888 "test".into(),
2889 r#"operation a(){(foo,bar)->foo+bar=foo->foo"#.into(),
2890 )],
2891 None,
2892 );
2893 let (std_id, store) =
2894 crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all());
2895 match Interpreter::new(
2896 sources,
2897 PackageType::Lib,
2898 TargetCapabilityFlags::all(),
2899 LanguageFeatures::default(),
2900 store,
2901 &[(std_id, None)],
2902 ) {
2903 Ok(_) => panic!("interpreter should fail with error"),
2904 Err(errors) => {
2905 is_error(
2906 &errors,
2907 &expect![[r#"
2908 syntax error: expected `:`, found `{`
2909 [test] [{]
2910 syntax error: expected `}`, found EOF
2911 [test] []
2912 type error: unsupported recursive type constraint
2913 [test] [(foo,bar)->foo+bar]
2914 type error: insufficient type information to infer type
2915 [test] [foo+bar]
2916 "#]],
2917 );
2918 }
2919 }
2920 }
2921 }
2922}