microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/qiskit2-explore

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

519lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::{Compiler, Increment};
5use crate::{
6 compile::{self, CompileUnit, PackageStore},
7 incremental::Error,
8};
9use expect_test::{Expect, expect};
10use indoc::indoc;
11use miette::Diagnostic;
12use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags};
13use std::fmt::Write;
14
15#[allow(clippy::too_many_lines)]
16#[test]
17fn one_callable() {
18 let store = PackageStore::new(compile::core());
19 let mut compiler = Compiler::new(
20 &store,
21 &[],
22 TargetCapabilityFlags::all(),
23 LanguageFeatures::default(),
24 );
25 let unit = compiler
26 .compile_fragments(
27 &mut CompileUnit::default(),
28 "test_1",
29 "namespace Foo { operation Main() : Unit {} }",
30 fail_on_error,
31 )
32 .expect("compilation should succeed");
33
34 check_unit(
35 &expect![[r#"
36 ast:
37 Package 0:
38 Namespace 1 [0-44] (Ident 2 [10-13] "Foo"):
39 Item 3 [16-42]:
40 Callable 4 [16-42] (Operation):
41 name: Ident 5 [26-30] "Main"
42 input: Pat 6 [30-32]: Unit
43 output: Type 7 [35-39]: Path: Path 8 [35-39] (Ident 9 [35-39] "Unit")
44 body: Block: Block 10 [40-42]: <empty>
45 names:
46 node_id:2,node_id:5,node_id:8,
47 terms:
48 node_id:6,node_id:10,
49 locals:
50 Locals {
51 scopes: [
52 Scope {
53 span: Span {
54 lo: 0,
55 hi: 4294967295,
56 },
57 kind: Block,
58 opens: {},
59 tys: {},
60 terms: {},
61 importables: {},
62 vars: {},
63 ty_vars: {},
64 },
65 Scope {
66 span: Span {
67 lo: 0,
68 hi: 44,
69 },
70 kind: Namespace(
71 NamespaceId(
72 5,
73 ),
74 ),
75 opens: {
76 None: [
77 Open {
78 namespace: NamespaceId(
79 5,
80 ),
81 span: Span {
82 lo: 10,
83 hi: 13,
84 },
85 },
86 ],
87 },
88 tys: {},
89 terms: {},
90 importables: {},
91 vars: {},
92 ty_vars: {},
93 },
94 Scope {
95 span: Span {
96 lo: 16,
97 hi: 42,
98 },
99 kind: Callable,
100 opens: {},
101 tys: {},
102 terms: {},
103 importables: {},
104 vars: {},
105 ty_vars: {},
106 },
107 Scope {
108 span: Span {
109 lo: 40,
110 hi: 42,
111 },
112 kind: Block,
113 opens: {},
114 tys: {},
115 terms: {},
116 importables: {},
117 vars: {},
118 ty_vars: {},
119 },
120 ],
121 }
122 hir:
123 Package:
124 Item 0 [0-44] (Public):
125 Namespace (Ident 5 [10-13] "Foo"): Item 1
126 Item 1 [16-42] (Internal):
127 Parent: 0
128 Callable 0 [16-42] (operation):
129 name: Ident 1 [26-30] "Main"
130 input: Pat 2 [30-32] [Type Unit]: Unit
131 output: Unit
132 functors: empty set
133 body: SpecDecl 3 [16-42]: Impl:
134 Block 4 [40-42]: <empty>
135 adj: <none>
136 ctl: <none>
137 ctl-adj: <none>"#]],
138 &unit,
139 );
140}
141
142#[test]
143fn one_statement() {
144 let store = PackageStore::new(compile::core());
145 let mut compiler = Compiler::new(
146 &store,
147 &[],
148 TargetCapabilityFlags::all(),
149 LanguageFeatures::default(),
150 );
151 let unit = compiler
152 .compile_fragments(
153 &mut CompileUnit::default(),
154 "test_1",
155 "use q = Qubit();",
156 fail_on_error,
157 )
158 .expect("compilation should succeed");
159
160 check_unit(
161 &expect![[r#"
162 ast:
163 Package 0:
164 Stmt 1 [0-16]: Qubit (Fresh)
165 Pat 2 [4-5]: Bind:
166 Ident 3 [4-5] "q"
167 QubitInit 4 [8-15] Single
168 names:
169 node_id:3,
170 terms:
171 node_id:1,node_id:2,node_id:3,node_id:4,
172 locals:
173 Locals {
174 scopes: [
175 Scope {
176 span: Span {
177 lo: 0,
178 hi: 4294967295,
179 },
180 kind: Block,
181 opens: {},
182 tys: {},
183 terms: {},
184 importables: {},
185 vars: {
186 "q": (
187 16,
188 NodeId(
189 3,
190 ),
191 ),
192 },
193 ty_vars: {},
194 },
195 ],
196 }
197 hir:
198 Package:
199 Stmt 0 [0-16]: Qubit (Fresh)
200 Pat 1 [4-5] [Type Qubit]: Bind: Ident 2 [4-5] "q"
201 QubitInit 3 [8-15] [Type Qubit]: Single"#]],
202 &unit,
203 );
204}
205
206#[test]
207fn parse_error() {
208 let store = PackageStore::new(compile::core());
209 let mut compiler = Compiler::new(
210 &store,
211 &[],
212 TargetCapabilityFlags::all(),
213 LanguageFeatures::default(),
214 );
215 let errors = compiler
216 .compile_fragments(&mut CompileUnit::default(), "test_1", "}}", fail_on_error)
217 .expect_err("should fail");
218
219 expect![[r#"
220 [
221 WithSource {
222 sources: [
223 Source {
224 name: "test_1",
225 contents: "}}",
226 offset: 0,
227 },
228 ],
229 error: Error(
230 Parse(
231 Error(
232 Token(
233 Eof,
234 Close(
235 Brace,
236 ),
237 Span {
238 lo: 0,
239 hi: 1,
240 },
241 ),
242 ),
243 ),
244 ),
245 },
246 ]
247 "#]]
248 .assert_debug_eq(&errors);
249}
250
251#[test]
252fn conditional_compilation_not_available() {
253 let store = PackageStore::new(compile::core());
254 let mut compiler = Compiler::new(
255 &store,
256 &[],
257 TargetCapabilityFlags::all(),
258 LanguageFeatures::default(),
259 );
260 let errors = compiler
261 .compile_fragments(
262 &mut CompileUnit::default(),
263 "test_1",
264 indoc! {"
265 @Config(Base)
266 function Dropped() : Unit {}
267
268 function Usage() : Unit {
269 Dropped();
270 }
271 "},
272 fail_on_error,
273 )
274 .expect_err("should fail");
275
276 assert!(!errors.is_empty());
277}
278
279#[test]
280fn errors_across_multiple_lines() {
281 let mut store = PackageStore::new(compile::core());
282 let std_id = store.insert(compile::std(&store, TargetCapabilityFlags::all()));
283 let mut compiler = Compiler::new(
284 &store,
285 &[(std_id, None)],
286 TargetCapabilityFlags::all(),
287 LanguageFeatures::default(),
288 );
289 let mut unit = CompileUnit::default();
290 compiler
291 .compile_fragments(
292 &mut unit,
293 "line_1",
294 "namespace Other { operation DumpMachine() : Unit { } }",
295 fail_on_error,
296 )
297 .expect("should succeed");
298
299 compiler
300 .compile_fragments(&mut unit, "line_2", "open Other;", fail_on_error)
301 .expect("should succeed");
302
303 compiler
304 .compile_fragments(
305 &mut unit,
306 "line_3",
307 "open Microsoft.Quantum.Diagnostics;",
308 fail_on_error,
309 )
310 .expect("should succeed");
311
312 let errors = compiler
313 .compile_fragments(&mut unit, "line_4", "DumpMachine()", fail_on_error)
314 .expect_err("should fail");
315
316 // Here we're validating that the compiler is able to return
317 // error labels mapping to different lines.
318 // The `Ambiguous` error is chosen as a test case because
319 // it contains multiple spans.
320 let labels = errors
321 .iter()
322 .flat_map(|e| e.labels().into_iter().flatten())
323 .map(|l| {
324 unit.sources
325 .find_by_offset(u32::try_from(l.offset()).expect("offset should fit into u32"))
326 .map(|s| &s.name)
327 })
328 .collect::<Vec<_>>();
329
330 expect![[r#"
331 [
332 Some(
333 "line_4",
334 ),
335 Some(
336 "line_2",
337 ),
338 Some(
339 "line_3",
340 ),
341 Some(
342 "line_4",
343 ),
344 ]
345 "#]]
346 .assert_debug_eq(&labels);
347}
348
349#[test]
350fn continue_after_parse_error() {
351 let store = PackageStore::new(compile::core());
352 let mut compiler = Compiler::new(
353 &store,
354 &Vec::new(),
355 TargetCapabilityFlags::all(),
356 LanguageFeatures::default(),
357 );
358 let mut errors = Vec::new();
359
360 compiler
361 .compile_fragments(
362 &mut CompileUnit::default(),
363 "test_1",
364 "operation Main() : Foo {
365 }}",
366 |e| -> Result<(), ()> {
367 errors.extend(e);
368 Ok(())
369 },
370 )
371 .expect("compile_fragments should succeed");
372
373 expect![[r#"
374 [
375 WithSource {
376 sources: [
377 Source {
378 name: "test_1",
379 contents: "operation Main() : Foo {\n }}",
380 offset: 0,
381 },
382 ],
383 error: Error(
384 Parse(
385 Error(
386 Token(
387 Eof,
388 Close(
389 Brace,
390 ),
391 Span {
392 lo: 38,
393 hi: 39,
394 },
395 ),
396 ),
397 ),
398 ),
399 },
400 WithSource {
401 sources: [
402 Source {
403 name: "test_1",
404 contents: "operation Main() : Foo {\n }}",
405 offset: 0,
406 },
407 ],
408 error: Error(
409 Resolve(
410 NotFound(
411 "Foo",
412 Span {
413 lo: 19,
414 hi: 22,
415 },
416 ),
417 ),
418 ),
419 },
420 ]
421 "#]]
422 .assert_debug_eq(&errors);
423}
424
425#[test]
426fn continue_after_lower_error() {
427 let store = PackageStore::new(compile::core());
428 let mut compiler = Compiler::new(
429 &store,
430 &[],
431 TargetCapabilityFlags::all(),
432 LanguageFeatures::default(),
433 );
434 let mut unit = CompileUnit::default();
435
436 let mut errors = Vec::new();
437
438 compiler
439 .compile_fragments(
440 &mut unit,
441 "test_1",
442 "operation A(q : Qubit) : Unit is Adj {
443 adjoint ... {}
444 }",
445 |e| -> Result<(), ()> {
446 errors = e;
447 Ok(())
448 },
449 )
450 .expect("compile_fragments should succeed");
451
452 expect![[r#"
453 [
454 WithSource {
455 sources: [
456 Source {
457 name: "test_1",
458 contents: "operation A(q : Qubit) : Unit is Adj {\n adjoint ... {}\n }",
459 offset: 0,
460 },
461 ],
462 error: Error(
463 Lower(
464 MissingBody(
465 Span {
466 lo: 0,
467 hi: 83,
468 },
469 ),
470 ),
471 ),
472 },
473 ]
474 "#]].assert_debug_eq(&errors);
475}
476
477fn check_unit(expect: &Expect, actual: &Increment) {
478 let ast = format!("ast:\n{}", actual.ast.package);
479
480 let names = format!(
481 "\nnames:\n{}",
482 actual
483 .ast
484 .names
485 .iter()
486 .fold(String::new(), |mut output, n| {
487 let _ = write!(output, "node_id:{},", n.0);
488 output
489 })
490 );
491 let terms = format!(
492 "\nterms:\n{}",
493 actual
494 .ast
495 .tys
496 .terms
497 .iter()
498 .fold(String::new(), |mut output, n| {
499 let _ = write!(output, "node_id:{},", n.0);
500 output
501 })
502 );
503 let locals = format!("\nlocals:\n{:#?}", actual.ast.locals);
504
505 let hir = format!("\nhir:\n{}", actual.hir);
506
507 expect.assert_eq(
508 &[ast, names, terms, locals, hir]
509 .into_iter()
510 .collect::<String>(),
511 );
512}
513
514fn fail_on_error(errors: Vec<Error>) -> Result<(), Vec<Error>> {
515 if !errors.is_empty() {
516 return Err(errors);
517 }
518 Ok(())
519}
520