microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.25.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

524lines · 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 Some(
347 "line_4",
348 ),
349 ]
350 "#]]
351 .assert_debug_eq(&labels);
352}
353
354#[test]
355fn continue_after_parse_error() {
356 let store = PackageStore::new(compile::core());
357 let mut compiler = Compiler::new(
358 &store,
359 &Vec::new(),
360 TargetCapabilityFlags::all(),
361 LanguageFeatures::default(),
362 );
363 let mut errors = Vec::new();
364
365 compiler
366 .compile_fragments(
367 &mut CompileUnit::new(store.peek_package_id()),
368 "test_1",
369 "operation Main() : Foo {
370 }}",
371 |e| -> Result<(), ()> {
372 errors.extend(e);
373 Ok(())
374 },
375 )
376 .expect("compile_fragments should succeed");
377
378 expect![[r#"
379 [
380 WithSource {
381 sources: [
382 Source {
383 name: "test_1",
384 contents: "operation Main() : Foo {\n }}",
385 offset: 0,
386 },
387 ],
388 error: Error(
389 Parse(
390 Error(
391 Token(
392 Eof,
393 Close(
394 Brace,
395 ),
396 Span {
397 lo: 38,
398 hi: 39,
399 },
400 ),
401 ),
402 ),
403 ),
404 },
405 WithSource {
406 sources: [
407 Source {
408 name: "test_1",
409 contents: "operation Main() : Foo {\n }}",
410 offset: 0,
411 },
412 ],
413 error: Error(
414 Resolve(
415 NotFound(
416 "Foo",
417 Span {
418 lo: 19,
419 hi: 22,
420 },
421 ),
422 ),
423 ),
424 },
425 ]
426 "#]]
427 .assert_debug_eq(&errors);
428}
429
430#[test]
431fn continue_after_lower_error() {
432 let store = PackageStore::new(compile::core());
433 let mut compiler = Compiler::new(
434 &store,
435 &[],
436 TargetCapabilityFlags::all(),
437 LanguageFeatures::default(),
438 );
439 let mut unit = CompileUnit::new(store.peek_package_id());
440
441 let mut errors = Vec::new();
442
443 compiler
444 .compile_fragments(
445 &mut unit,
446 "test_1",
447 "operation A(q : Qubit) : Unit is Adj {
448 adjoint ... {}
449 }",
450 |e| -> Result<(), ()> {
451 errors = e;
452 Ok(())
453 },
454 )
455 .expect("compile_fragments should succeed");
456
457 expect![[r#"
458 [
459 WithSource {
460 sources: [
461 Source {
462 name: "test_1",
463 contents: "operation A(q : Qubit) : Unit is Adj {\n adjoint ... {}\n }",
464 offset: 0,
465 },
466 ],
467 error: Error(
468 Lower(
469 MissingBody(
470 Span {
471 lo: 0,
472 hi: 83,
473 },
474 ),
475 ),
476 ),
477 },
478 ]
479 "#]].assert_debug_eq(&errors);
480}
481
482fn check_unit(expect: &Expect, actual: &Increment) {
483 let ast = format!("ast:\n{}", actual.ast.package);
484
485 let names = format!(
486 "\nnames:\n{}",
487 actual
488 .ast
489 .names
490 .iter()
491 .fold(String::new(), |mut output, n| {
492 let _ = write!(output, "node_id:{},", n.0);
493 output
494 })
495 );
496 let terms = format!(
497 "\nterms:\n{}",
498 actual
499 .ast
500 .tys
501 .terms
502 .iter()
503 .fold(String::new(), |mut output, n| {
504 let _ = write!(output, "node_id:{},", n.0);
505 output
506 })
507 );
508 let locals = format!("\nlocals:\n{:#?}", actual.ast.locals);
509
510 let hir = format!("\nhir:\n{}", actual.hir);
511
512 expect.assert_eq(
513 &[ast, names, terms, locals, hir]
514 .into_iter()
515 .collect::<String>(),
516 );
517}
518
519fn fail_on_error(errors: Vec<Error>) -> Result<(), Vec<Error>> {
520 if !errors.is_empty() {
521 return Err(errors);
522 }
523 Ok(())
524}