microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

521lines · 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::new(store.peek_package_id()),
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::new(store.peek_package_id()),
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(
217 &mut CompileUnit::new(store.peek_package_id()),
218 "test_1",
219 "}}",
220 fail_on_error,
221 )
222 .expect_err("should fail");
223
224 expect![[r#"
225 [
226 WithSource {
227 sources: [
228 Source {
229 name: "test_1",
230 contents: "}}",
231 offset: 0,
232 },
233 ],
234 error: Error(
235 Parse(
236 Error(
237 Token(
238 Eof,
239 Close(
240 Brace,
241 ),
242 Span {
243 lo: 0,
244 hi: 1,
245 },
246 ),
247 ),
248 ),
249 ),
250 },
251 ]
252 "#]]
253 .assert_debug_eq(&errors);
254}
255
256#[test]
257fn conditional_compilation_not_available() {
258 let store = PackageStore::new(compile::core());
259 let mut compiler = Compiler::new(
260 &store,
261 &[],
262 TargetCapabilityFlags::all(),
263 LanguageFeatures::default(),
264 );
265 let errors = compiler
266 .compile_fragments(
267 &mut CompileUnit::new(store.peek_package_id()),
268 "test_1",
269 indoc! {"
270 @Config(Base)
271 function Dropped() : Unit {}
272
273 function Usage() : Unit {
274 Dropped();
275 }
276 "},
277 fail_on_error,
278 )
279 .expect_err("should fail");
280
281 assert!(!errors.is_empty());
282}
283
284#[test]
285fn errors_across_multiple_lines() {
286 let mut store = PackageStore::new(compile::core());
287 let std_id = store.insert(compile::std(&store, TargetCapabilityFlags::all()));
288 let mut compiler = Compiler::new(
289 &store,
290 &[(std_id, None)],
291 TargetCapabilityFlags::all(),
292 LanguageFeatures::default(),
293 );
294 let mut unit = CompileUnit::new(store.peek_package_id());
295 compiler
296 .compile_fragments(
297 &mut unit,
298 "line_1",
299 "namespace Other { operation DumpMachine() : Unit { } }",
300 fail_on_error,
301 )
302 .expect("should succeed");
303
304 compiler
305 .compile_fragments(&mut unit, "line_2", "open Other;", fail_on_error)
306 .expect("should succeed");
307
308 compiler
309 .compile_fragments(
310 &mut unit,
311 "line_3",
312 "open Microsoft.Quantum.Diagnostics;",
313 fail_on_error,
314 )
315 .expect("should succeed");
316
317 let errors = compiler
318 .compile_fragments(&mut unit, "line_4", "DumpMachine()", fail_on_error)
319 .expect_err("should fail");
320
321 // Here we're validating that the compiler is able to return
322 // error labels mapping to different lines.
323 // The `Ambiguous` error is chosen as a test case because
324 // it contains multiple spans.
325 let labels = errors
326 .iter()
327 .flat_map(|e| e.labels().into_iter().flatten())
328 .map(|l| {
329 unit.sources
330 .find_by_offset(u32::try_from(l.offset()).expect("offset should fit into u32"))
331 .map(|s| &s.name)
332 })
333 .collect::<Vec<_>>();
334
335 expect![[r#"
336 [
337 Some(
338 "line_4",
339 ),
340 Some(
341 "line_2",
342 ),
343 Some(
344 "line_3",
345 ),
346 ]
347 "#]]
348 .assert_debug_eq(&labels);
349}
350
351#[test]
352fn continue_after_parse_error() {
353 let store = PackageStore::new(compile::core());
354 let mut compiler = Compiler::new(
355 &store,
356 &Vec::new(),
357 TargetCapabilityFlags::all(),
358 LanguageFeatures::default(),
359 );
360 let mut errors = Vec::new();
361
362 compiler
363 .compile_fragments(
364 &mut CompileUnit::new(store.peek_package_id()),
365 "test_1",
366 "operation Main() : Foo {
367 }}",
368 |e| -> Result<(), ()> {
369 errors.extend(e);
370 Ok(())
371 },
372 )
373 .expect("compile_fragments should succeed");
374
375 expect![[r#"
376 [
377 WithSource {
378 sources: [
379 Source {
380 name: "test_1",
381 contents: "operation Main() : Foo {\n }}",
382 offset: 0,
383 },
384 ],
385 error: Error(
386 Parse(
387 Error(
388 Token(
389 Eof,
390 Close(
391 Brace,
392 ),
393 Span {
394 lo: 38,
395 hi: 39,
396 },
397 ),
398 ),
399 ),
400 ),
401 },
402 WithSource {
403 sources: [
404 Source {
405 name: "test_1",
406 contents: "operation Main() : Foo {\n }}",
407 offset: 0,
408 },
409 ],
410 error: Error(
411 Resolve(
412 NotFound(
413 "Foo",
414 Span {
415 lo: 19,
416 hi: 22,
417 },
418 ),
419 ),
420 ),
421 },
422 ]
423 "#]]
424 .assert_debug_eq(&errors);
425}
426
427#[test]
428fn continue_after_lower_error() {
429 let store = PackageStore::new(compile::core());
430 let mut compiler = Compiler::new(
431 &store,
432 &[],
433 TargetCapabilityFlags::all(),
434 LanguageFeatures::default(),
435 );
436 let mut unit = CompileUnit::new(store.peek_package_id());
437
438 let mut errors = Vec::new();
439
440 compiler
441 .compile_fragments(
442 &mut unit,
443 "test_1",
444 "operation A(q : Qubit) : Unit is Adj {
445 adjoint ... {}
446 }",
447 |e| -> Result<(), ()> {
448 errors = e;
449 Ok(())
450 },
451 )
452 .expect("compile_fragments should succeed");
453
454 expect![[r#"
455 [
456 WithSource {
457 sources: [
458 Source {
459 name: "test_1",
460 contents: "operation A(q : Qubit) : Unit is Adj {\n adjoint ... {}\n }",
461 offset: 0,
462 },
463 ],
464 error: Error(
465 Lower(
466 MissingBody(
467 Span {
468 lo: 0,
469 hi: 83,
470 },
471 ),
472 ),
473 ),
474 },
475 ]
476 "#]].assert_debug_eq(&errors);
477}
478
479fn check_unit(expect: &Expect, actual: &Increment) {
480 let ast = format!("ast:\n{}", actual.ast.package);
481
482 let names = format!(
483 "\nnames:\n{}",
484 actual
485 .ast
486 .names
487 .iter()
488 .fold(String::new(), |mut output, n| {
489 let _ = write!(output, "node_id:{},", n.0);
490 output
491 })
492 );
493 let terms = format!(
494 "\nterms:\n{}",
495 actual
496 .ast
497 .tys
498 .terms
499 .iter()
500 .fold(String::new(), |mut output, n| {
501 let _ = write!(output, "node_id:{},", n.0);
502 output
503 })
504 );
505 let locals = format!("\nlocals:\n{:#?}", actual.ast.locals);
506
507 let hir = format!("\nhir:\n{}", actual.hir);
508
509 expect.assert_eq(
510 &[ast, names, terms, locals, hir]
511 .into_iter()
512 .collect::<String>(),
513 );
514}
515
516fn fail_on_error(errors: Vec<Error>) -> Result<(), Vec<Error>> {
517 if !errors.is_empty() {
518 return Err(errors);
519 }
520 Ok(())
521}
522