microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billt/revert-mimalloc

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_frontend/src/incremental/tests.rs

501lines · modecode

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