microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/openqasm-extern-compilation

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc_frontend/src/compile/tests.rs

1487lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4mod multiple_packages;
5
6use std::{rc::Rc, sync::Arc};
7
8use super::{CompileUnit, Error, PackageStore, SourceMap, compile, longest_common_prefix};
9use crate::compile::TargetCapabilityFlags;
10
11use expect_test::expect;
12use indoc::indoc;
13use miette::Diagnostic;
14use qsc_data_structures::{language_features::LanguageFeatures, span::Span};
15use qsc_hir::{
16 global,
17 hir::{
18 Block, Expr, ExprKind, ItemId, ItemKind, Lit, LocalItemId, NodeId, Res, SpecBody, Stmt,
19 StmtKind,
20 },
21 mut_visit::MutVisitor,
22 ty::{Prim, Ty},
23};
24
25fn error_span(error: &Error) -> Span {
26 let label = error
27 .labels()
28 .and_then(|mut ls| ls.next())
29 .expect("error should have at least one label");
30
31 let span = label.inner();
32 let offset = span
33 .offset()
34 .try_into()
35 .expect("span offset should fit into u32");
36 let len: u32 = span.len().try_into().expect("span len should fit into u32");
37 Span {
38 lo: offset,
39 hi: offset + len,
40 }
41}
42
43fn source_span<'a>(sources: &'a SourceMap, error: &Error) -> (&'a str, Span) {
44 let span = error_span(error);
45 let source = sources
46 .find_by_offset(span.lo)
47 .expect("offset should match at least one source");
48 (
49 &source.name,
50 Span {
51 lo: span.lo - source.offset,
52 hi: span.hi - source.offset,
53 },
54 )
55}
56
57/// runs a compile with the default configuration
58fn default_compile(sources: SourceMap) -> CompileUnit {
59 compile(
60 &PackageStore::new(super::core()),
61 &[],
62 sources,
63 TargetCapabilityFlags::all(),
64 LanguageFeatures::default(),
65 )
66}
67
68#[test]
69fn one_file_no_entry() {
70 let sources = SourceMap::new(
71 [(
72 "test".into(),
73 indoc! {"
74 namespace Foo {
75 function A() : Unit {}
76 }
77 "}
78 .into(),
79 )],
80 None,
81 );
82
83 let unit = default_compile(sources);
84 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
85
86 let entry = unit.package.entry.as_ref();
87 assert!(entry.is_none(), "{entry:#?}");
88}
89
90#[test]
91fn one_file_error() {
92 let sources = SourceMap::new(
93 [(
94 "test".into(),
95 indoc! {"
96 namespace Foo {
97 function A() : Unit {
98 x
99 }
100 }
101 "}
102 .into(),
103 )],
104 None,
105 );
106
107 let unit = default_compile(sources);
108 let errors: Vec<_> = unit
109 .errors
110 .iter()
111 .map(|error| source_span(&unit.sources, error))
112 .collect();
113
114 assert_eq!(vec![("test", Span { lo: 50, hi: 51 })], errors);
115}
116
117#[test]
118fn two_files_dependency() {
119 let sources = SourceMap::new(
120 [
121 (
122 "test1".into(),
123 indoc! {"
124 namespace Foo {
125 function A() : Unit {}
126 }
127 "}
128 .into(),
129 ),
130 (
131 "test2".into(),
132 indoc! {"
133 namespace Foo {
134 function B() : Unit {
135 A();
136 }
137 }
138 "}
139 .into(),
140 ),
141 ],
142 None,
143 );
144
145 let unit = default_compile(sources);
146 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
147}
148
149#[test]
150fn two_files_mutual_dependency() {
151 let sources = SourceMap::new(
152 [
153 (
154 "test1".into(),
155 indoc! {"
156 namespace Foo {
157 function A() : Unit {
158 B();
159 }
160 }
161 "}
162 .into(),
163 ),
164 (
165 "test2".into(),
166 indoc! {"
167 namespace Foo {
168 function B() : Unit {
169 A();
170 }
171 }
172 "}
173 .into(),
174 ),
175 ],
176 None,
177 );
178
179 let unit = default_compile(sources);
180 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
181}
182
183#[test]
184fn two_files_error() {
185 let sources = SourceMap::new(
186 [
187 (
188 "test1".into(),
189 indoc! {"
190 namespace Foo {
191 function A() : Unit {}
192 }
193 "}
194 .into(),
195 ),
196 (
197 "test2".into(),
198 indoc! {"
199 namespace Foo {
200 function B() : Unit {
201 C();
202 }
203 }
204 "}
205 .into(),
206 ),
207 ],
208 None,
209 );
210
211 let unit = default_compile(sources);
212 let errors: Vec<_> = unit
213 .errors
214 .iter()
215 .map(|error| source_span(&unit.sources, error))
216 .collect();
217
218 assert_eq!(
219 vec![
220 ("test2", Span { lo: 50, hi: 51 }),
221 ("test2", Span { lo: 50, hi: 53 }),
222 ],
223 errors
224 );
225}
226
227#[test]
228fn entry_call_operation() {
229 let sources = SourceMap::new(
230 [(
231 "test".into(),
232 indoc! {"
233 namespace Foo {
234 operation A() : Unit {}
235 }
236 "}
237 .into(),
238 )],
239 Some("Foo.A()".into()),
240 );
241
242 let unit = default_compile(sources);
243 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
244
245 let entry = &unit.package.entry.expect("package should have entry");
246 let ExprKind::Call(callee, _) = &entry.kind else {
247 panic!("entry should be a call")
248 };
249 let ExprKind::Var(res, _) = &callee.kind else {
250 panic!("callee should be a variable")
251 };
252 assert_eq!(
253 &Res::Item(ItemId {
254 package: None,
255 item: LocalItemId::from(1),
256 }),
257 res
258 );
259}
260
261#[test]
262fn entry_error() {
263 let sources = SourceMap::new(
264 [(
265 "test".into(),
266 indoc! {"
267 namespace Foo {
268 operation A() : Unit {}
269 }
270 "}
271 .into(),
272 )],
273 Some("Foo.B()".into()),
274 );
275
276 let unit = default_compile(sources);
277 assert_eq!(
278 ("<entry>", Span { lo: 0, hi: 5 }),
279 source_span(&unit.sources, &unit.errors[0])
280 );
281}
282
283#[test]
284fn replace_node() {
285 struct Replacer;
286
287 impl MutVisitor for Replacer {
288 fn visit_expr(&mut self, expr: &mut Expr) {
289 *expr = Expr {
290 id: NodeId::default(),
291 span: expr.span,
292 ty: Ty::Prim(Prim::Int),
293 kind: ExprKind::Lit(Lit::Int(2)),
294 };
295 }
296 }
297
298 let sources = SourceMap::new(
299 [(
300 "test".into(),
301 indoc! {"
302 namespace A {
303 function Foo() : Int {
304 1
305 }
306 }
307 "}
308 .into(),
309 )],
310 None,
311 );
312
313 let mut unit = default_compile(sources);
314 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
315 Replacer.visit_package(&mut unit.package);
316 unit.assigner.visit_package(&mut unit.package);
317
318 let ItemKind::Callable(callable) = &unit
319 .package
320 .items
321 .get(LocalItemId::from(1))
322 .expect("package should have item")
323 .kind
324 else {
325 panic!("item should be a callable");
326 };
327 let SpecBody::Impl(_, block) = &callable.body.body else {
328 panic!("callable body have a block")
329 };
330 expect![[r#"
331 Block 4 [39-56] [Type Int]:
332 Stmt 5 [49-50]: Expr: Expr 8 [49-50] [Type Int]: Lit: Int(2)"#]]
333 .assert_eq(&block.to_string());
334}
335
336#[test]
337fn insert_core_call() {
338 struct Inserter<'a> {
339 core: &'a global::Table,
340 }
341
342 impl MutVisitor for Inserter<'_> {
343 fn visit_block(&mut self, block: &mut Block) {
344 let ns = self
345 .core
346 .find_namespace(["QIR", "Runtime"].iter().copied())
347 .expect("QIR runtime should be inserted at instantiation of core Table");
348 let allocate = self
349 .core
350 .resolve_callable(ns, "__quantum__rt__qubit_allocate")
351 .expect("qubit allocation should be in core");
352 let allocate_ty = allocate
353 .scheme
354 .instantiate(&[])
355 .expect("qubit allocation scheme should instantiate");
356 let callee = Expr {
357 id: NodeId::default(),
358 span: Span::default(),
359 ty: Ty::Arrow(Rc::new(allocate_ty)),
360 kind: ExprKind::Var(Res::Item(allocate.id), Vec::new()),
361 };
362
363 let arg = Expr {
364 id: NodeId::default(),
365 span: Span::default(),
366 ty: Ty::UNIT,
367 kind: ExprKind::Tuple(Vec::new()),
368 };
369
370 let call = Expr {
371 id: NodeId::default(),
372 span: Span::default(),
373 ty: Ty::Prim(Prim::Qubit),
374 kind: ExprKind::Call(Box::new(callee), Box::new(arg)),
375 };
376
377 block.stmts.push(Stmt {
378 id: NodeId::default(),
379 span: Span::default(),
380 kind: StmtKind::Semi(call),
381 });
382 }
383 }
384
385 let sources = SourceMap::new(
386 [(
387 "test".into(),
388 indoc! {"
389 namespace A {
390 operation Foo() : () {}
391 }
392 "}
393 .into(),
394 )],
395 None,
396 );
397
398 let store = PackageStore::new(super::core());
399 let mut unit = default_compile(sources);
400 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
401 let mut inserter = Inserter { core: store.core() };
402 inserter.visit_package(&mut unit.package);
403 unit.assigner.visit_package(&mut unit.package);
404
405 expect![[r#"
406 Package:
407 Item 0 [0-43] (Public):
408 Namespace (Ident 5 [10-11] "A"): Item 1
409 Item 1 [18-41] (Internal):
410 Parent: 0
411 Callable 0 [18-41] (operation):
412 name: Ident 1 [28-31] "Foo"
413 input: Pat 2 [31-33] [Type Unit]: Unit
414 output: Unit
415 functors: empty set
416 body: SpecDecl 3 [18-41]: Impl:
417 Block 4 [39-41] [Type Unit]:
418 Stmt 6 [0-0]: Semi: Expr 7 [0-0] [Type Qubit]: Call:
419 Expr 8 [0-0] [Type (Unit => Qubit)]: Var: Item 6 (Package 0)
420 Expr 9 [0-0] [Type Unit]: Unit
421 adj: <none>
422 ctl: <none>
423 ctl-adj: <none>"#]]
424 .assert_eq(&unit.package.to_string());
425}
426
427#[test]
428fn package_dependency() {
429 let mut store = PackageStore::new(super::core());
430
431 let sources1 = SourceMap::new(
432 [(
433 "test".into(),
434 indoc! {"
435 namespace Package1 {
436 function Foo() : Int {
437 1
438 }
439 export Foo;
440 }
441 "}
442 .into(),
443 )],
444 None,
445 );
446 let unit1 = compile(
447 &store,
448 &[],
449 sources1,
450 TargetCapabilityFlags::all(),
451 LanguageFeatures::default(),
452 );
453 assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
454 let package1 = store.insert(unit1);
455
456 let sources2 = SourceMap::new(
457 [(
458 "test".into(),
459 indoc! {"
460 namespace Package2 {
461 function Bar() : Int {
462 PackageAlias.Package1.Foo()
463 }
464 }
465 "}
466 .into(),
467 )],
468 None,
469 );
470 let unit2 = compile(
471 &store,
472 &[(package1, Some(Arc::from("PackageAlias")))],
473 sources2,
474 TargetCapabilityFlags::all(),
475 LanguageFeatures::default(),
476 );
477 assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
478
479 expect![[r#"
480 Package:
481 Item 0 [0-91] (Public):
482 Namespace (Ident 9 [10-18] "Package2"): Item 1
483 Item 1 [25-89] (Internal):
484 Parent: 0
485 Callable 0 [25-89] (function):
486 name: Ident 1 [34-37] "Bar"
487 input: Pat 2 [37-39] [Type Unit]: Unit
488 output: Int
489 functors: empty set
490 body: SpecDecl 3 [25-89]: Impl:
491 Block 4 [46-89] [Type Int]:
492 Stmt 5 [56-83]: Expr: Expr 6 [56-83] [Type Int]: Call:
493 Expr 7 [56-81] [Type (Unit -> Int)]: Var: Item 1 (Package 1)
494 Expr 8 [81-83] [Type Unit]: Unit
495 adj: <none>
496 ctl: <none>
497 ctl-adj: <none>"#]]
498 .assert_eq(&unit2.package.to_string());
499}
500
501#[test]
502fn package_dependency_internal_error() {
503 let mut store = PackageStore::new(super::core());
504
505 let sources1 = SourceMap::new(
506 [(
507 "test".into(),
508 indoc! {"
509 namespace Package1 {
510 internal function Foo() : Int {
511 1
512 }
513 }
514 "}
515 .into(),
516 )],
517 None,
518 );
519 let unit1 = compile(
520 &store,
521 &[],
522 sources1,
523 TargetCapabilityFlags::all(),
524 LanguageFeatures::default(),
525 );
526 assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
527 let package1 = store.insert(unit1);
528
529 let sources2 = SourceMap::new(
530 [(
531 "test".into(),
532 indoc! {"
533 namespace Package2 {
534 function Bar() : Int {
535 Package1.Foo()
536 }
537 }
538 "}
539 .into(),
540 )],
541 None,
542 );
543 let unit2 = compile(
544 &store,
545 &[(package1, Some(Arc::from("PackageAlias")))],
546 sources2,
547 TargetCapabilityFlags::all(),
548 LanguageFeatures::default(),
549 );
550
551 let errors: Vec<_> = unit2
552 .errors
553 .iter()
554 .map(|error| source_span(&unit2.sources, error))
555 .collect();
556 assert_eq!(vec![("test", Span { lo: 56, hi: 68 }),], errors);
557
558 expect![[r#"
559 Package:
560 Item 0 [0-78] (Public):
561 Namespace (Ident 9 [10-18] "Package2"): Item 1
562 Item 1 [25-76] (Internal):
563 Parent: 0
564 Callable 0 [25-76] (function):
565 name: Ident 1 [34-37] "Bar"
566 input: Pat 2 [37-39] [Type Unit]: Unit
567 output: Int
568 functors: empty set
569 body: SpecDecl 3 [25-76]: Impl:
570 Block 4 [46-76] [Type Int]:
571 Stmt 5 [56-70]: Expr: Expr 6 [56-70] [Type Int]: Call:
572 Expr 7 [56-68] [Type ?]: Var: Err
573 Expr 8 [68-70] [Type Unit]: Unit
574 adj: <none>
575 ctl: <none>
576 ctl-adj: <none>"#]]
577 .assert_eq(&unit2.package.to_string());
578}
579
580#[test]
581fn package_dependency_udt() {
582 let mut store = PackageStore::new(super::core());
583
584 let sources1 = SourceMap::new(
585 [(
586 "test".into(),
587 indoc! {"
588 namespace Package1 {
589 newtype Bar = Int;
590 function Foo(bar : Bar) : Int {
591 bar!
592 }
593 export Foo, Bar;
594 }
595 "}
596 .into(),
597 )],
598 None,
599 );
600 let unit1 = compile(
601 &store,
602 &[],
603 sources1,
604 TargetCapabilityFlags::all(),
605 LanguageFeatures::default(),
606 );
607 assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
608 let package1 = store.insert(unit1);
609
610 let sources2 = SourceMap::new(
611 [(
612 "test".into(),
613 indoc! {"
614 namespace Package2 {
615 function Baz() : Int {
616 PackageAlias.Package1.Foo(PackageAlias.Package1.Bar(1))
617 }
618 }
619 "}
620 .into(),
621 )],
622 None,
623 );
624 let unit2 = compile(
625 &store,
626 &[(package1, Some(Arc::from("PackageAlias")))],
627 sources2,
628 TargetCapabilityFlags::all(),
629 LanguageFeatures::default(),
630 );
631 assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
632
633 expect![[r#"
634 Package:
635 Item 0 [0-119] (Public):
636 Namespace (Ident 11 [10-18] "Package2"): Item 1
637 Item 1 [25-117] (Internal):
638 Parent: 0
639 Callable 0 [25-117] (function):
640 name: Ident 1 [34-37] "Baz"
641 input: Pat 2 [37-39] [Type Unit]: Unit
642 output: Int
643 functors: empty set
644 body: SpecDecl 3 [25-117]: Impl:
645 Block 4 [46-117] [Type Int]:
646 Stmt 5 [56-111]: Expr: Expr 6 [56-111] [Type Int]: Call:
647 Expr 7 [56-81] [Type (UDT<"Bar": Item 1 (Package 1)> -> Int)]: Var: Item 2 (Package 1)
648 Expr 8 [82-110] [Type UDT<"Bar": Item 1 (Package 1)>]: Call:
649 Expr 9 [82-107] [Type (Int -> UDT<"Bar": Item 1 (Package 1)>)]: Var: Item 1 (Package 1)
650 Expr 10 [108-109] [Type Int]: Lit: Int(1)
651 adj: <none>
652 ctl: <none>
653 ctl-adj: <none>"#]]
654 .assert_eq(&unit2.package.to_string());
655}
656
657#[test]
658fn package_dependency_nested_udt() {
659 let mut store = PackageStore::new(super::core());
660
661 let sources1 = SourceMap::new(
662 [(
663 "test".into(),
664 indoc! {"
665 namespace Package1 {
666 newtype Bar = Int;
667 newtype Baz = Int;
668 newtype Foo = (bar : Bar, Baz);
669 export Bar, Baz, Foo;
670 }
671 "}
672 .into(),
673 )],
674 None,
675 );
676 let unit1 = compile(
677 &store,
678 &[],
679 sources1,
680 TargetCapabilityFlags::all(),
681 LanguageFeatures::default(),
682 );
683 assert!(unit1.errors.is_empty(), "{:#?}", unit1.errors);
684 let package1 = store.insert(unit1);
685
686 let sources2 = SourceMap::new(
687 [(
688 "test".into(),
689 indoc! {"
690 namespace Package2 {
691 import PackageAlias.*;
692 function Test() : Int {
693 let bar = Package1.Bar(1);
694 let baz = Package1.Baz(2);
695 let foo = Package1.Foo(bar, baz);
696 let inner : Package1.Bar = foo::bar;
697 let (_, other : Package1.Baz) = foo!;
698 inner!
699 }
700 }
701 "}
702 .into(),
703 )],
704 None,
705 );
706 let unit2 = compile(
707 &store,
708 &[(package1, Some(Arc::from("PackageAlias")))],
709 sources2,
710 TargetCapabilityFlags::all(),
711 LanguageFeatures::default(),
712 );
713 assert!(unit2.errors.is_empty(), "{:#?}", unit2.errors);
714
715 expect![[r#"
716 Package:
717 Item 0 [0-301] (Public):
718 Namespace (Ident 40 [10-18] "Package2"): Item 1
719 Item 1 [52-299] (Internal):
720 Parent: 0
721 Callable 0 [52-299] (function):
722 name: Ident 1 [61-65] "Test"
723 input: Pat 2 [65-67] [Type Unit]: Unit
724 output: Int
725 functors: empty set
726 body: SpecDecl 3 [52-299]: Impl:
727 Block 4 [74-299] [Type Int]:
728 Stmt 5 [84-110]: Local (Immutable):
729 Pat 6 [88-91] [Type UDT<"Bar": Item 1 (Package 1)>]: Bind: Ident 7 [88-91] "bar"
730 Expr 8 [94-109] [Type UDT<"Bar": Item 1 (Package 1)>]: Call:
731 Expr 9 [94-106] [Type (Int -> UDT<"Bar": Item 1 (Package 1)>)]: Var: Item 1 (Package 1)
732 Expr 10 [107-108] [Type Int]: Lit: Int(1)
733 Stmt 11 [119-145]: Local (Immutable):
734 Pat 12 [123-126] [Type UDT<"Baz": Item 2 (Package 1)>]: Bind: Ident 13 [123-126] "baz"
735 Expr 14 [129-144] [Type UDT<"Baz": Item 2 (Package 1)>]: Call:
736 Expr 15 [129-141] [Type (Int -> UDT<"Baz": Item 2 (Package 1)>)]: Var: Item 2 (Package 1)
737 Expr 16 [142-143] [Type Int]: Lit: Int(2)
738 Stmt 17 [154-187]: Local (Immutable):
739 Pat 18 [158-161] [Type UDT<"Foo": Item 3 (Package 1)>]: Bind: Ident 19 [158-161] "foo"
740 Expr 20 [164-186] [Type UDT<"Foo": Item 3 (Package 1)>]: Call:
741 Expr 21 [164-176] [Type ((UDT<"Bar": Item 1 (Package 1)>, UDT<"Baz": Item 2 (Package 1)>) -> UDT<"Foo": Item 3 (Package 1)>)]: Var: Item 3 (Package 1)
742 Expr 22 [176-186] [Type (UDT<"Bar": Item 1 (Package 1)>, UDT<"Baz": Item 2 (Package 1)>)]: Tuple:
743 Expr 23 [177-180] [Type UDT<"Bar": Item 1 (Package 1)>]: Var: Local 7
744 Expr 24 [182-185] [Type UDT<"Baz": Item 2 (Package 1)>]: Var: Local 13
745 Stmt 25 [196-232]: Local (Immutable):
746 Pat 26 [200-220] [Type UDT<"Bar": Item 1 (Package 1)>]: Bind: Ident 27 [200-205] "inner"
747 Expr 28 [223-231] [Type UDT<"Bar": Item 1 (Package 1)>]: Field:
748 Expr 29 [223-226] [Type UDT<"Foo": Item 3 (Package 1)>]: Var: Local 19
749 Path(FieldPath { indices: [0] })
750 Stmt 30 [241-278]: Local (Immutable):
751 Pat 31 [245-270] [Type (UDT<"Bar": Item 1 (Package 1)>, UDT<"Baz": Item 2 (Package 1)>)]: Tuple:
752 Pat 32 [246-247] [Type UDT<"Bar": Item 1 (Package 1)>]: Discard
753 Pat 33 [249-269] [Type UDT<"Baz": Item 2 (Package 1)>]: Bind: Ident 34 [249-254] "other"
754 Expr 35 [273-277] [Type (UDT<"Bar": Item 1 (Package 1)>, UDT<"Baz": Item 2 (Package 1)>)]: UnOp (Unwrap):
755 Expr 36 [273-276] [Type UDT<"Foo": Item 3 (Package 1)>]: Var: Local 19
756 Stmt 37 [287-293]: Expr: Expr 38 [287-293] [Type Int]: UnOp (Unwrap):
757 Expr 39 [287-292] [Type UDT<"Bar": Item 1 (Package 1)>]: Var: Local 27
758 adj: <none>
759 ctl: <none>
760 ctl-adj: <none>"#]]
761 .assert_eq(&unit2.package.to_string());
762}
763
764#[test]
765fn std_dependency() {
766 let mut store = PackageStore::new(super::core());
767 let std = store.insert(super::std(&store, TargetCapabilityFlags::all()));
768 let sources = SourceMap::new(
769 [(
770 "test".into(),
771 indoc! {"
772 namespace Foo {
773 import Std.Intrinsic.*;
774
775 operation Main() : Unit {
776 use q = Qubit();
777 X(q);
778 }
779 }
780 "}
781 .into(),
782 )],
783 Some("Foo.Main()".into()),
784 );
785
786 let unit = compile(
787 &store,
788 &[(std, None)],
789 sources,
790 TargetCapabilityFlags::all(),
791 LanguageFeatures::default(),
792 );
793 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
794}
795
796#[test]
797fn std_dependency_base_profile() {
798 let mut store = PackageStore::new(super::core());
799 let std = store.insert(super::std(&store, TargetCapabilityFlags::empty()));
800 let sources = SourceMap::new(
801 [(
802 "test".into(),
803 indoc! {"
804 namespace Foo {
805 import Std.Intrinsic.*;
806
807 operation Main() : Unit {
808 use q = Qubit();
809 X(q);
810 }
811 }
812 "}
813 .into(),
814 )],
815 Some("Foo.Main()".into()),
816 );
817
818 let unit = compile(
819 &store,
820 &[(std, None)],
821 sources,
822 TargetCapabilityFlags::empty(),
823 LanguageFeatures::default(),
824 );
825 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
826}
827
828#[test]
829fn introduce_prelude_ambiguity() {
830 let mut store = PackageStore::new(super::core());
831 let std = store.insert(super::std(&store, TargetCapabilityFlags::all()));
832 let sources = SourceMap::new(
833 [(
834 "test".into(),
835 indoc! {"namespace Microsoft.Quantum.Canon {
836 function Length () : () { }
837 }
838 namespace Foo {
839 function Main (): () { Length }
840 }"}
841 .into(),
842 )],
843 Some("Foo.Main()".into()),
844 );
845
846 let unit = compile(
847 &store,
848 &[(std, None)],
849 sources,
850 TargetCapabilityFlags::all(),
851 LanguageFeatures::default(),
852 );
853 let errors: Vec<Error> = unit.errors;
854 assert!(
855 errors.len() == 1
856 && matches!(
857 errors[0],
858 Error(super::ErrorKind::Resolve(
859 super::resolve::Error::AmbiguousPrelude { .. }
860 ))
861 )
862 );
863}
864
865#[test]
866fn entry_parse_error() {
867 let sources = SourceMap::new(
868 [(
869 "test".into(),
870 "namespace Foo { operation B() : Unit {} }".into(),
871 )],
872 Some("Foo.B)".into()),
873 );
874
875 let unit = default_compile(sources);
876
877 assert_eq!(
878 unit.errors[0]
879 .code()
880 .expect("expected error code")
881 .to_string(),
882 "Qsc.Parse.Token"
883 );
884
885 assert_eq!(
886 ("<entry>", Span { lo: 5, hi: 6 }),
887 source_span(&unit.sources, &unit.errors[0])
888 );
889}
890
891#[test]
892fn two_files_error_eof() {
893 let sources = SourceMap::new(
894 [
895 ("test1".into(), "namespace Foo {".into()),
896 ("test2".into(), "namespace Bar {}".into()),
897 ],
898 None,
899 );
900
901 let unit = default_compile(sources);
902 let errors: Vec<_> = unit
903 .errors
904 .iter()
905 .map(|error| source_span(&unit.sources, error))
906 .collect();
907
908 assert_eq!(vec![("test1", Span { lo: 15, hi: 15 }),], errors);
909
910 expect![[r#"
911 Package:
912 Item 0 [0-15] (Public):
913 Namespace (Ident 0 [10-13] "Foo"): <empty>
914 Item 1 [16-32] (Public):
915 Namespace (Ident 1 [26-29] "Bar"): <empty>"#]]
916 .assert_eq(&unit.package.to_string());
917}
918
919#[test]
920fn unimplemented_call_from_dependency_produces_error() {
921 let lib_sources = SourceMap::new(
922 [(
923 "lib".into(),
924 indoc! {"
925 namespace Foo {
926 @Unimplemented()
927 operation Bar() : Unit {}
928 export Bar;
929 }
930 "}
931 .into(),
932 )],
933 None,
934 );
935 let mut store = PackageStore::new(super::core());
936 let lib = compile(
937 &store,
938 &[],
939 lib_sources,
940 TargetCapabilityFlags::all(),
941 LanguageFeatures::default(),
942 );
943 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
944 let lib = store.insert(lib);
945
946 let sources = SourceMap::new(
947 [(
948 "test".into(),
949 indoc! {"
950 namespace Test {
951 open Foo;
952 operation Main() : Unit {
953 Bar();
954 }
955 }
956 "}
957 .into(),
958 )],
959 None,
960 );
961 let unit = compile(
962 &store,
963 &[(lib, None)],
964 sources,
965 TargetCapabilityFlags::all(),
966 LanguageFeatures::default(),
967 );
968 expect![[r#"
969 [
970 Error(
971 Resolve(
972 Unimplemented(
973 "Bar",
974 Span {
975 lo: 69,
976 hi: 72,
977 },
978 ),
979 ),
980 ),
981 ]
982 "#]]
983 .assert_debug_eq(&unit.errors);
984}
985
986#[test]
987fn unimplemented_attribute_call_within_unit_error() {
988 let sources = SourceMap::new(
989 [(
990 "test".into(),
991 indoc! {"
992 namespace Foo {
993 @Unimplemented()
994 operation Bar() : Unit {}
995 operation Baz() : Unit {
996 Bar();
997 }
998 }
999 "}
1000 .into(),
1001 )],
1002 None,
1003 );
1004 let unit = default_compile(sources);
1005 expect![[r#"
1006 [
1007 Error(
1008 Resolve(
1009 Unimplemented(
1010 "Bar",
1011 Span {
1012 lo: 104,
1013 hi: 107,
1014 },
1015 ),
1016 ),
1017 ),
1018 ]
1019 "#]]
1020 .assert_debug_eq(&unit.errors);
1021}
1022
1023#[test]
1024fn unimplemented_attribute_with_non_unit_expr_error() {
1025 let sources = SourceMap::new(
1026 [(
1027 "test".into(),
1028 indoc! {"
1029 namespace Foo {
1030 @Unimplemented(1)
1031 operation Bar() : Unit {}
1032 }
1033 "}
1034 .into(),
1035 )],
1036 None,
1037 );
1038 let unit = default_compile(sources);
1039 expect![[r#"
1040 [
1041 Error(
1042 Lower(
1043 InvalidAttrArgs(
1044 "()",
1045 Span {
1046 lo: 34,
1047 hi: 37,
1048 },
1049 ),
1050 ),
1051 ),
1052 ]
1053 "#]]
1054 .assert_debug_eq(&unit.errors);
1055}
1056
1057#[test]
1058fn unimplemented_attribute_avoids_ambiguous_error_with_duplicate_names_in_scope() {
1059 let lib_sources = SourceMap::new(
1060 [(
1061 "lib".into(),
1062 indoc! {"
1063 namespace Foo {
1064 @Unimplemented()
1065 operation Bar() : Unit {}
1066 }
1067 "}
1068 .into(),
1069 )],
1070 None,
1071 );
1072 let mut store = PackageStore::new(super::core());
1073 let lib = compile(
1074 &store,
1075 &[],
1076 lib_sources,
1077 TargetCapabilityFlags::all(),
1078 LanguageFeatures::default(),
1079 );
1080 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1081 let lib = store.insert(lib);
1082
1083 let sources = SourceMap::new(
1084 [(
1085 "test".into(),
1086 indoc! {"
1087 namespace Dependency {
1088 operation Bar() : Unit {}
1089 }
1090 namespace Test {
1091 open Foo;
1092 open Dependency;
1093 operation Main() : Unit {
1094 Bar();
1095 }
1096 }
1097 "}
1098 .into(),
1099 )],
1100 None,
1101 );
1102 let unit = compile(
1103 &store,
1104 &[(lib, None)],
1105 sources,
1106 TargetCapabilityFlags::all(),
1107 LanguageFeatures::default(),
1108 );
1109 expect![[r#"
1110 []
1111 "#]]
1112 .assert_debug_eq(&unit.errors);
1113}
1114
1115#[test]
1116fn duplicate_intrinsic_from_dependency() {
1117 let lib_sources = SourceMap::new(
1118 [(
1119 "lib".into(),
1120 indoc! {"
1121 namespace Foo {
1122 operation Bar() : Unit { body intrinsic; }
1123 }
1124 "}
1125 .into(),
1126 )],
1127 None,
1128 );
1129
1130 let mut store = PackageStore::new(super::core());
1131 let lib = compile(
1132 &store,
1133 &[],
1134 lib_sources,
1135 TargetCapabilityFlags::all(),
1136 LanguageFeatures::default(),
1137 );
1138 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1139 let lib = store.insert(lib);
1140
1141 let sources = SourceMap::new(
1142 [(
1143 "test".into(),
1144 indoc! {"
1145 namespace Test {
1146 operation Bar() : Unit { body intrinsic; }
1147 }
1148 "}
1149 .into(),
1150 )],
1151 None,
1152 );
1153
1154 let unit = compile(
1155 &store,
1156 &[(lib, None)],
1157 sources,
1158 TargetCapabilityFlags::all(),
1159 LanguageFeatures::default(),
1160 );
1161 expect![[r#"
1162 [
1163 Error(
1164 Resolve(
1165 DuplicateIntrinsic(
1166 "Bar",
1167 Span {
1168 lo: 31,
1169 hi: 34,
1170 },
1171 ),
1172 ),
1173 ),
1174 ]
1175 "#]]
1176 .assert_debug_eq(&unit.errors);
1177}
1178
1179#[test]
1180fn reject_use_qubit_block_syntax_if_preview_feature_is_on() {
1181 let mut store = PackageStore::new(super::core());
1182 let std = store.insert(super::std(&store, TargetCapabilityFlags::empty()));
1183 let sources = SourceMap::new(
1184 [(
1185 "test".into(),
1186 indoc! {"
1187 namespace Foo {
1188 import Std.Intrinsic.*;
1189 operation Main() : Unit {
1190 use q = Qubit() {
1191 // some qubit operation here
1192 // this should be a syntax error because
1193 // we have the v2 preview syntax feature enabled
1194 X(q);
1195 };
1196
1197 }
1198 }
1199 "}
1200 .into(),
1201 )],
1202 Some("Foo.Main()".into()),
1203 );
1204
1205 let unit = compile(
1206 &store,
1207 &[(std, None)],
1208 sources,
1209 TargetCapabilityFlags::empty(),
1210 LanguageFeatures::V2PreviewSyntax,
1211 );
1212 expect![[r#"
1213 [
1214 Error(
1215 Parse(
1216 Error(
1217 Token(
1218 Semi,
1219 Open(
1220 Brace,
1221 ),
1222 Span {
1223 lo: 109,
1224 hi: 110,
1225 },
1226 ),
1227 ),
1228 ),
1229 ),
1230 ]
1231 "#]]
1232 .assert_debug_eq(&unit.errors);
1233}
1234
1235#[test]
1236fn accept_use_qubit_block_syntax_if_preview_feature_is_off() {
1237 let mut store = PackageStore::new(super::core());
1238 let std = store.insert(super::std(&store, TargetCapabilityFlags::empty()));
1239 let sources = SourceMap::new(
1240 [(
1241 "test".into(),
1242 indoc! {"
1243 namespace Foo {
1244 import Std.Intrinsic.*;
1245 operation Main() : Unit {
1246 use q = Qubit() {
1247 // some qubit operation here
1248 // this should be a syntax error because
1249 // we have the v2 preview syntax feature enabled
1250 X(q);
1251 };
1252 }
1253 }
1254 "}
1255 .into(),
1256 )],
1257 Some("Foo.Main()".into()),
1258 );
1259
1260 let unit = compile(
1261 &store,
1262 &[(std, None)],
1263 sources,
1264 TargetCapabilityFlags::empty(),
1265 LanguageFeatures::default(),
1266 );
1267 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
1268}
1269
1270#[test]
1271fn hierarchical_namespace_basic() {
1272 let lib_sources = SourceMap::new(
1273 [(
1274 "lib".into(),
1275 indoc! {"
1276 namespace Foo.Bar {
1277 operation Baz() : Unit {}
1278 }
1279 namespace Main {
1280 open Foo;
1281 operation Main() : Unit {
1282 Bar.Baz();
1283 }
1284 }
1285 "}
1286 .into(),
1287 )],
1288 None,
1289 );
1290
1291 let store = PackageStore::new(super::core());
1292 let lib = compile(
1293 &store,
1294 &[],
1295 lib_sources,
1296 TargetCapabilityFlags::all(),
1297 LanguageFeatures::default(),
1298 );
1299 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1300}
1301
1302#[test]
1303fn implicit_namespace_basic() {
1304 let sources = SourceMap::new(
1305 [
1306 (
1307 "Test.qs".into(),
1308 indoc! {"
1309 operation Bar() : Unit {}
1310 "}
1311 .into(),
1312 ),
1313 (
1314 "Main.qs".into(),
1315 indoc! {"
1316 @EntryPoint()
1317 operation Bar() : Unit {
1318 Test.Bar();
1319 open Foo.Bar;
1320 Baz.Quux();
1321 }
1322 "}
1323 .into(),
1324 ),
1325 (
1326 "Foo/Bar/Baz.qs".into(),
1327 indoc! {"
1328 operation Quux() : Unit {}
1329 "}
1330 .into(),
1331 ),
1332 ],
1333 None,
1334 );
1335 let unit = default_compile(sources);
1336 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
1337}
1338
1339#[test]
1340fn bad_filename_implicit_namespace_best_effort_fixup() {
1341 let sources = SourceMap::new(
1342 [
1343 // Rejected for starting with number
1344 (
1345 "123Test.qs".into(),
1346 indoc! {"
1347 operation Bar() : Unit {}
1348 "}
1349 .into(),
1350 ),
1351 // Cleaned up by replacing '-' with '_'
1352 (
1353 "Test-File.qs".into(),
1354 indoc! {"
1355 operation Bar() : Unit {
1356 }
1357 "}
1358 .into(),
1359 ),
1360 // Rejected for containing '.'
1361 (
1362 "Namespace.Foo.qs".into(),
1363 indoc! {"
1364 operation Bar() : Unit {}
1365 "}
1366 .into(),
1367 ),
1368 ],
1369 None,
1370 );
1371 let unit = default_compile(sources);
1372 expect![[r#"
1373 [
1374 Error(
1375 Parse(
1376 Error(
1377 InvalidFileName(
1378 Span {
1379 lo: 0,
1380 hi: 25,
1381 },
1382 "123Test",
1383 ),
1384 ),
1385 ),
1386 ),
1387 Error(
1388 Parse(
1389 Error(
1390 InvalidFileName(
1391 Span {
1392 lo: 55,
1393 hi: 80,
1394 },
1395 "Namespace.Foo",
1396 ),
1397 ),
1398 ),
1399 ),
1400 ]
1401 "#]]
1402 .assert_debug_eq(&unit.errors);
1403}
1404
1405#[test]
1406fn test_longest_common_prefix_1() {
1407 assert_eq!(longest_common_prefix(&["/a/b/c", "/a/b/d"]), "/a/b/");
1408}
1409
1410#[test]
1411fn test_longest_common_prefix_2() {
1412 assert_eq!(longest_common_prefix(&["foo", "bar"]), "");
1413}
1414
1415#[test]
1416fn test_longest_common_prefix_3() {
1417 assert_eq!(longest_common_prefix(&["baz", "bar"]), "");
1418}
1419
1420#[test]
1421fn test_longest_common_prefix_4() {
1422 assert_eq!(longest_common_prefix(&["baz", "bar"]), "");
1423}
1424
1425#[test]
1426fn test_longest_common_prefix_5() {
1427 assert_eq!(
1428 longest_common_prefix(&[
1429 "code\\project\\src\\Main.qs",
1430 "code\\project\\src\\Helper.qs"
1431 ]),
1432 "code\\project\\src\\"
1433 );
1434}
1435
1436#[test]
1437fn test_longest_common_prefix_6() {
1438 assert_eq!(
1439 longest_common_prefix(&["code/project/src/Bar.qs", "code/project/src/Baz.qs"]),
1440 "code/project/src/"
1441 );
1442}
1443
1444#[test]
1445fn test_longest_common_prefix_two_relative_paths() {
1446 expect!["a/"].assert_eq(longest_common_prefix(&["a/b", "a/c"]));
1447}
1448
1449#[test]
1450fn test_longest_common_prefix_one_relative_path() {
1451 expect!["a/"].assert_eq(longest_common_prefix(&["a/b"]));
1452}
1453
1454#[test]
1455fn test_longest_common_prefix_one_file_name() {
1456 expect![""].assert_eq(longest_common_prefix(&["a"]));
1457}
1458
1459#[test]
1460fn test_longest_common_prefix_only_root_common() {
1461 expect!["/"].assert_eq(longest_common_prefix(&["/a/b", "/b/c"]));
1462}
1463
1464#[test]
1465fn test_longest_common_prefix_only_root_common_no_leading() {
1466 expect![""].assert_eq(longest_common_prefix(&["a/b", "b/c"]));
1467}
1468
1469#[test]
1470fn export_namespace_with_same_name_as_newtype_does_not_cause_panic() {
1471 let sources = SourceMap::new(
1472 [(
1473 "test".into(),
1474 indoc! {"
1475 namespace A {
1476 export A;
1477 newtype A = Int;
1478 }
1479 "}
1480 .into(),
1481 )],
1482 None,
1483 );
1484
1485 let unit = default_compile(sources);
1486 expect!["[]"].assert_eq(&format!("{:?}", unit.errors));
1487}
1488