microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.19.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

1491lines · 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_term(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 4 (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// this test is ignored for now -- see
920// https://github.com/microsoft/qsharp/pull/1698#discussion_r1664575343 for more information.
921// if we want to use `Unimplemented` more seriously (it is currently not used anywhere),
922// we should consider how it will interact with exports and other features.
923#[ignore = "see above link to discussion"]
924#[test]
925fn unimplemented_call_from_dependency_produces_error() {
926 let lib_sources = SourceMap::new(
927 [(
928 "lib".into(),
929 indoc! {"
930 namespace Foo {
931 @Unimplemented()
932 operation Bar() : Unit {}
933 }
934 "}
935 .into(),
936 )],
937 None,
938 );
939 let mut store = PackageStore::new(super::core());
940 let lib = compile(
941 &store,
942 &[],
943 lib_sources,
944 TargetCapabilityFlags::all(),
945 LanguageFeatures::default(),
946 );
947 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
948 let lib = store.insert(lib);
949
950 let sources = SourceMap::new(
951 [(
952 "test".into(),
953 indoc! {"
954 namespace Test {
955 open Foo;
956 operation Main() : Unit {
957 Bar();
958 }
959 }
960 "}
961 .into(),
962 )],
963 None,
964 );
965 let unit = compile(
966 &store,
967 &[(lib, None)],
968 sources,
969 TargetCapabilityFlags::all(),
970 LanguageFeatures::default(),
971 );
972 expect![[r#"
973 [
974 Error(
975 Resolve(
976 Unimplemented(
977 "Bar",
978 Span {
979 lo: 69,
980 hi: 72,
981 },
982 ),
983 ),
984 ),
985 ]
986 "#]]
987 .assert_debug_eq(&unit.errors);
988}
989
990#[test]
991fn unimplemented_attribute_call_within_unit_error() {
992 let sources = SourceMap::new(
993 [(
994 "test".into(),
995 indoc! {"
996 namespace Foo {
997 @Unimplemented()
998 operation Bar() : Unit {}
999 operation Baz() : Unit {
1000 Bar();
1001 }
1002 }
1003 "}
1004 .into(),
1005 )],
1006 None,
1007 );
1008 let unit = default_compile(sources);
1009 expect![[r#"
1010 [
1011 Error(
1012 Resolve(
1013 Unimplemented(
1014 "Bar",
1015 Span {
1016 lo: 104,
1017 hi: 107,
1018 },
1019 ),
1020 ),
1021 ),
1022 ]
1023 "#]]
1024 .assert_debug_eq(&unit.errors);
1025}
1026
1027#[test]
1028fn unimplemented_attribute_with_non_unit_expr_error() {
1029 let sources = SourceMap::new(
1030 [(
1031 "test".into(),
1032 indoc! {"
1033 namespace Foo {
1034 @Unimplemented(1)
1035 operation Bar() : Unit {}
1036 }
1037 "}
1038 .into(),
1039 )],
1040 None,
1041 );
1042 let unit = default_compile(sources);
1043 expect![[r#"
1044 [
1045 Error(
1046 Lower(
1047 InvalidAttrArgs(
1048 "()",
1049 Span {
1050 lo: 34,
1051 hi: 37,
1052 },
1053 ),
1054 ),
1055 ),
1056 ]
1057 "#]]
1058 .assert_debug_eq(&unit.errors);
1059}
1060
1061#[test]
1062fn unimplemented_attribute_avoids_ambiguous_error_with_duplicate_names_in_scope() {
1063 let lib_sources = SourceMap::new(
1064 [(
1065 "lib".into(),
1066 indoc! {"
1067 namespace Foo {
1068 @Unimplemented()
1069 operation Bar() : Unit {}
1070 }
1071 "}
1072 .into(),
1073 )],
1074 None,
1075 );
1076 let mut store = PackageStore::new(super::core());
1077 let lib = compile(
1078 &store,
1079 &[],
1080 lib_sources,
1081 TargetCapabilityFlags::all(),
1082 LanguageFeatures::default(),
1083 );
1084 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1085 let lib = store.insert(lib);
1086
1087 let sources = SourceMap::new(
1088 [(
1089 "test".into(),
1090 indoc! {"
1091 namespace Dependency {
1092 operation Bar() : Unit {}
1093 }
1094 namespace Test {
1095 open Foo;
1096 open Dependency;
1097 operation Main() : Unit {
1098 Bar();
1099 }
1100 }
1101 "}
1102 .into(),
1103 )],
1104 None,
1105 );
1106 let unit = compile(
1107 &store,
1108 &[(lib, None)],
1109 sources,
1110 TargetCapabilityFlags::all(),
1111 LanguageFeatures::default(),
1112 );
1113 expect![[r#"
1114 []
1115 "#]]
1116 .assert_debug_eq(&unit.errors);
1117}
1118
1119#[test]
1120fn duplicate_intrinsic_from_dependency() {
1121 let lib_sources = SourceMap::new(
1122 [(
1123 "lib".into(),
1124 indoc! {"
1125 namespace Foo {
1126 operation Bar() : Unit { body intrinsic; }
1127 }
1128 "}
1129 .into(),
1130 )],
1131 None,
1132 );
1133
1134 let mut store = PackageStore::new(super::core());
1135 let lib = compile(
1136 &store,
1137 &[],
1138 lib_sources,
1139 TargetCapabilityFlags::all(),
1140 LanguageFeatures::default(),
1141 );
1142 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1143 let lib = store.insert(lib);
1144
1145 let sources = SourceMap::new(
1146 [(
1147 "test".into(),
1148 indoc! {"
1149 namespace Test {
1150 operation Bar() : Unit { body intrinsic; }
1151 }
1152 "}
1153 .into(),
1154 )],
1155 None,
1156 );
1157
1158 let unit = compile(
1159 &store,
1160 &[(lib, None)],
1161 sources,
1162 TargetCapabilityFlags::all(),
1163 LanguageFeatures::default(),
1164 );
1165 expect![[r#"
1166 [
1167 Error(
1168 Resolve(
1169 DuplicateIntrinsic(
1170 "Bar",
1171 Span {
1172 lo: 31,
1173 hi: 34,
1174 },
1175 ),
1176 ),
1177 ),
1178 ]
1179 "#]]
1180 .assert_debug_eq(&unit.errors);
1181}
1182
1183#[test]
1184fn reject_use_qubit_block_syntax_if_preview_feature_is_on() {
1185 let mut store = PackageStore::new(super::core());
1186 let std = store.insert(super::std(&store, TargetCapabilityFlags::empty()));
1187 let sources = SourceMap::new(
1188 [(
1189 "test".into(),
1190 indoc! {"
1191 namespace Foo {
1192 import Std.Intrinsic.*;
1193 operation Main() : Unit {
1194 use q = Qubit() {
1195 // some qubit operation here
1196 // this should be a syntax error because
1197 // we have the v2 preview syntax feature enabled
1198 X(q);
1199 };
1200
1201 }
1202 }
1203 "}
1204 .into(),
1205 )],
1206 Some("Foo.Main()".into()),
1207 );
1208
1209 let unit = compile(
1210 &store,
1211 &[(std, None)],
1212 sources,
1213 TargetCapabilityFlags::empty(),
1214 LanguageFeatures::V2PreviewSyntax,
1215 );
1216 expect![[r#"
1217 [
1218 Error(
1219 Parse(
1220 Error(
1221 Token(
1222 Semi,
1223 Open(
1224 Brace,
1225 ),
1226 Span {
1227 lo: 109,
1228 hi: 110,
1229 },
1230 ),
1231 ),
1232 ),
1233 ),
1234 ]
1235 "#]]
1236 .assert_debug_eq(&unit.errors);
1237}
1238
1239#[test]
1240fn accept_use_qubit_block_syntax_if_preview_feature_is_off() {
1241 let mut store = PackageStore::new(super::core());
1242 let std = store.insert(super::std(&store, TargetCapabilityFlags::empty()));
1243 let sources = SourceMap::new(
1244 [(
1245 "test".into(),
1246 indoc! {"
1247 namespace Foo {
1248 import Std.Intrinsic.*;
1249 operation Main() : Unit {
1250 use q = Qubit() {
1251 // some qubit operation here
1252 // this should be a syntax error because
1253 // we have the v2 preview syntax feature enabled
1254 X(q);
1255 };
1256 }
1257 }
1258 "}
1259 .into(),
1260 )],
1261 Some("Foo.Main()".into()),
1262 );
1263
1264 let unit = compile(
1265 &store,
1266 &[(std, None)],
1267 sources,
1268 TargetCapabilityFlags::empty(),
1269 LanguageFeatures::default(),
1270 );
1271 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
1272}
1273
1274#[test]
1275fn hierarchical_namespace_basic() {
1276 let lib_sources = SourceMap::new(
1277 [(
1278 "lib".into(),
1279 indoc! {"
1280 namespace Foo.Bar {
1281 operation Baz() : Unit {}
1282 }
1283 namespace Main {
1284 open Foo;
1285 operation Main() : Unit {
1286 Bar.Baz();
1287 }
1288 }
1289 "}
1290 .into(),
1291 )],
1292 None,
1293 );
1294
1295 let store = PackageStore::new(super::core());
1296 let lib = compile(
1297 &store,
1298 &[],
1299 lib_sources,
1300 TargetCapabilityFlags::all(),
1301 LanguageFeatures::default(),
1302 );
1303 assert!(lib.errors.is_empty(), "{:#?}", lib.errors);
1304}
1305
1306#[test]
1307fn implicit_namespace_basic() {
1308 let sources = SourceMap::new(
1309 [
1310 (
1311 "Test.qs".into(),
1312 indoc! {"
1313 operation Bar() : Unit {}
1314 "}
1315 .into(),
1316 ),
1317 (
1318 "Main.qs".into(),
1319 indoc! {"
1320 @EntryPoint()
1321 operation Bar() : Unit {
1322 Test.Bar();
1323 open Foo.Bar;
1324 Baz.Quux();
1325 }
1326 "}
1327 .into(),
1328 ),
1329 (
1330 "Foo/Bar/Baz.qs".into(),
1331 indoc! {"
1332 operation Quux() : Unit {}
1333 "}
1334 .into(),
1335 ),
1336 ],
1337 None,
1338 );
1339 let unit = default_compile(sources);
1340 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
1341}
1342
1343#[test]
1344fn bad_filename_implicit_namespace_best_effort_fixup() {
1345 let sources = SourceMap::new(
1346 [
1347 // Rejected for starting with number
1348 (
1349 "123Test.qs".into(),
1350 indoc! {"
1351 operation Bar() : Unit {}
1352 "}
1353 .into(),
1354 ),
1355 // Cleaned up by replacing '-' with '_'
1356 (
1357 "Test-File.qs".into(),
1358 indoc! {"
1359 operation Bar() : Unit {
1360 }
1361 "}
1362 .into(),
1363 ),
1364 // Rejected for containing '.'
1365 (
1366 "Namespace.Foo.qs".into(),
1367 indoc! {"
1368 operation Bar() : Unit {}
1369 "}
1370 .into(),
1371 ),
1372 ],
1373 None,
1374 );
1375 let unit = default_compile(sources);
1376 expect![[r#"
1377 [
1378 Error(
1379 Parse(
1380 Error(
1381 InvalidFileName(
1382 Span {
1383 lo: 0,
1384 hi: 25,
1385 },
1386 "123Test",
1387 ),
1388 ),
1389 ),
1390 ),
1391 Error(
1392 Parse(
1393 Error(
1394 InvalidFileName(
1395 Span {
1396 lo: 55,
1397 hi: 80,
1398 },
1399 "Namespace.Foo",
1400 ),
1401 ),
1402 ),
1403 ),
1404 ]
1405 "#]]
1406 .assert_debug_eq(&unit.errors);
1407}
1408
1409#[test]
1410fn test_longest_common_prefix_1() {
1411 assert_eq!(longest_common_prefix(&["/a/b/c", "/a/b/d"]), "/a/b/");
1412}
1413
1414#[test]
1415fn test_longest_common_prefix_2() {
1416 assert_eq!(longest_common_prefix(&["foo", "bar"]), "");
1417}
1418
1419#[test]
1420fn test_longest_common_prefix_3() {
1421 assert_eq!(longest_common_prefix(&["baz", "bar"]), "");
1422}
1423
1424#[test]
1425fn test_longest_common_prefix_4() {
1426 assert_eq!(longest_common_prefix(&["baz", "bar"]), "");
1427}
1428
1429#[test]
1430fn test_longest_common_prefix_5() {
1431 assert_eq!(
1432 longest_common_prefix(&[
1433 "code\\project\\src\\Main.qs",
1434 "code\\project\\src\\Helper.qs"
1435 ]),
1436 "code\\project\\src\\"
1437 );
1438}
1439
1440#[test]
1441fn test_longest_common_prefix_6() {
1442 assert_eq!(
1443 longest_common_prefix(&["code/project/src/Bar.qs", "code/project/src/Baz.qs"]),
1444 "code/project/src/"
1445 );
1446}
1447
1448#[test]
1449fn test_longest_common_prefix_two_relative_paths() {
1450 expect!["a/"].assert_eq(longest_common_prefix(&["a/b", "a/c"]));
1451}
1452
1453#[test]
1454fn test_longest_common_prefix_one_relative_path() {
1455 expect!["a/"].assert_eq(longest_common_prefix(&["a/b"]));
1456}
1457
1458#[test]
1459fn test_longest_common_prefix_one_file_name() {
1460 expect![""].assert_eq(longest_common_prefix(&["a"]));
1461}
1462
1463#[test]
1464fn test_longest_common_prefix_only_root_common() {
1465 expect!["/"].assert_eq(longest_common_prefix(&["/a/b", "/b/c"]));
1466}
1467
1468#[test]
1469fn test_longest_common_prefix_only_root_common_no_leading() {
1470 expect![""].assert_eq(longest_common_prefix(&["a/b", "b/c"]));
1471}
1472
1473#[test]
1474fn export_namespace_with_same_name_as_newtype_does_not_cause_panic() {
1475 let sources = SourceMap::new(
1476 [(
1477 "test".into(),
1478 indoc! {"
1479 namespace A {
1480 export A;
1481 newtype A = Int;
1482 }
1483 "}
1484 .into(),
1485 )],
1486 None,
1487 );
1488
1489 let unit = default_compile(sources);
1490 expect!["[]"].assert_eq(&format!("{:?}", unit.errors));
1491}
1492