microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/pythontelem

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_frontend/src/compile/tests.rs

1493lines · modecode

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