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_eval/src/lower.rs

927lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use qsc_data_structures::index_map::IndexMap;
5use qsc_fir::assigner::Assigner;
6use qsc_fir::fir::{Block, CallableImpl, ExecGraphNode, Expr, Pat, SpecImpl, Stmt};
7use qsc_fir::{
8 fir::{self, BlockId, ExprId, LocalItemId, PatId, StmtId},
9 ty::{Arrow, InferFunctorId, ParamId, Ty},
10};
11use qsc_hir::hir::{self, SpecBody, SpecGen};
12use std::iter::once;
13use std::{clone::Clone, rc::Rc};
14
15pub struct Lowerer {
16 nodes: IndexMap<hir::NodeId, fir::NodeId>,
17 locals: IndexMap<hir::NodeId, fir::LocalVarId>,
18 exprs: IndexMap<ExprId, Expr>,
19 pats: IndexMap<PatId, Pat>,
20 stmts: IndexMap<StmtId, Stmt>,
21 blocks: IndexMap<BlockId, Block>,
22 assigner: Assigner,
23 exec_graph: Vec<ExecGraphNode>,
24}
25
26impl Default for Lowerer {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl Lowerer {
33 #[must_use]
34 pub fn new() -> Self {
35 Self {
36 nodes: IndexMap::new(),
37 locals: IndexMap::new(),
38 exprs: IndexMap::new(),
39 pats: IndexMap::new(),
40 stmts: IndexMap::new(),
41 blocks: IndexMap::new(),
42 assigner: Assigner::new(),
43 exec_graph: Vec::new(),
44 }
45 }
46
47 pub fn take_exec_graph(&mut self) -> Vec<ExecGraphNode> {
48 self.exec_graph
49 .drain(..)
50 .chain(once(ExecGraphNode::Ret))
51 .collect()
52 }
53
54 pub fn lower_package(&mut self, package: &hir::Package) -> fir::Package {
55 let entry = package.entry.as_ref().map(|e| self.lower_expr(e));
56 let entry_exec_graph = self.exec_graph.drain(..).collect();
57 let items: IndexMap<LocalItemId, fir::Item> = package
58 .items
59 .values()
60 .map(|i| self.lower_item(i))
61 .map(|i| (i.id, i))
62 .collect();
63
64 // Lower top-level statements
65 for stmt in &package.stmts {
66 self.lower_stmt(stmt);
67 }
68
69 let blocks: IndexMap<_, _> = self.blocks.drain().collect();
70 let exprs: IndexMap<_, _> = self.exprs.drain().collect();
71 let pats: IndexMap<_, _> = self.pats.drain().collect();
72 let stmts: IndexMap<_, _> = self.stmts.drain().collect();
73
74 let package = fir::Package {
75 items,
76 entry,
77 entry_exec_graph,
78 blocks,
79 exprs,
80 pats,
81 stmts,
82 };
83 qsc_fir::validate::validate(&package);
84 package
85 }
86
87 /// Used to update the package with the lowered items.
88 /// Incremental compilation requires that we update the package
89 /// instead of returning a new one.
90 #[allow(clippy::similar_names)]
91 pub fn lower_and_update_package(
92 &mut self,
93 fir_package: &mut fir::Package,
94 hir_package: &hir::Package,
95 ) -> Vec<StmtId> {
96 let items: IndexMap<LocalItemId, fir::Item> = hir_package
97 .items
98 .values()
99 .map(|i| self.lower_item(i))
100 .map(|i| (i.id, i))
101 .collect();
102
103 let new_stmts = hir_package
104 .stmts
105 .iter()
106 .map(|s| self.lower_stmt(s))
107 .collect();
108
109 let entry = hir_package.entry.as_ref().map(|e| self.lower_expr(e));
110
111 self.update_package(fir_package);
112
113 for (k, v) in items {
114 fir_package.items.insert(k, v);
115 }
116
117 fir_package.entry = entry;
118
119 qsc_fir::validate::validate(fir_package);
120
121 new_stmts
122 }
123
124 fn update_package(&mut self, package: &mut fir::Package) {
125 for (id, value) in self.blocks.drain() {
126 package.blocks.insert(id, value);
127 }
128
129 for (id, value) in self.exprs.drain() {
130 package.exprs.insert(id, value);
131 }
132
133 for (id, value) in self.pats.drain() {
134 package.pats.insert(id, value);
135 }
136
137 for (id, value) in self.stmts.drain() {
138 package.stmts.insert(id, value);
139 }
140 }
141
142 fn lower_item(&mut self, item: &hir::Item) -> fir::Item {
143 let kind = match &item.kind {
144 hir::ItemKind::Namespace(name, items) => {
145 let name = self.lower_ident(name);
146 let items = items.iter().map(|i| lower_local_item_id(*i)).collect();
147 fir::ItemKind::Namespace(name, items)
148 }
149 hir::ItemKind::Callable(callable) => {
150 let callable = self.lower_callable_decl(callable);
151
152 fir::ItemKind::Callable(callable)
153 }
154 hir::ItemKind::Ty(name, udt) => {
155 let name = self.lower_ident(name);
156 let udt = self.lower_udt(udt);
157
158 fir::ItemKind::Ty(name, udt)
159 }
160 };
161 let attrs = lower_attrs(&item.attrs);
162 fir::Item {
163 id: lower_local_item_id(item.id),
164 span: item.span,
165 parent: item.parent.map(lower_local_item_id),
166 doc: Rc::clone(&item.doc),
167 attrs,
168 visibility: lower_visibility(item.visibility),
169 kind,
170 }
171 }
172
173 fn lower_callable_decl(&mut self, decl: &hir::CallableDecl) -> fir::CallableDecl {
174 self.assigner.stash_local();
175 let locals = self.locals.drain().collect::<Vec<_>>();
176
177 let id = self.lower_id(decl.id);
178 let kind = lower_callable_kind(decl.kind);
179 let name = self.lower_ident(&decl.name);
180 let input = self.lower_pat(&decl.input);
181 let generics = lower_generics(&decl.generics);
182 let output = self.lower_ty(&decl.output);
183 let functors = lower_functors(decl.functors);
184 let implementation = if decl.body.body == SpecBody::Gen(SpecGen::Intrinsic) {
185 assert!(
186 !(decl.adj.is_some() || decl.ctl.is_some() || decl.ctl_adj.is_some()),
187 "intrinsic callables should not have specializations"
188 );
189 CallableImpl::Intrinsic
190 } else {
191 let body = self.lower_spec_decl(&decl.body);
192 let adj = decl.adj.as_ref().map(|f| self.lower_spec_decl(f));
193 let ctl = decl.ctl.as_ref().map(|f| self.lower_spec_decl(f));
194 let ctl_adj = decl.ctl_adj.as_ref().map(|f| self.lower_spec_decl(f));
195 let specialized_implementation = SpecImpl {
196 body,
197 adj,
198 ctl,
199 ctl_adj,
200 };
201 CallableImpl::Spec(specialized_implementation)
202 };
203
204 self.assigner.reset_local();
205 self.locals.clear();
206 for (k, v) in locals {
207 self.locals.insert(k, v);
208 }
209
210 fir::CallableDecl {
211 id,
212 span: decl.span,
213 kind,
214 name,
215 generics,
216 input,
217 output,
218 functors,
219 implementation,
220 }
221 }
222
223 fn lower_spec_decl(&mut self, decl: &hir::SpecDecl) -> fir::SpecDecl {
224 let SpecBody::Impl(pat, block) = &decl.body else {
225 panic!("if a SpecDecl is some, then it must be an implementation");
226 };
227 let input = pat.as_ref().map(|p| self.lower_spec_decl_pat(p));
228 let block = self.lower_block(block);
229 fir::SpecDecl {
230 id: self.lower_id(decl.id),
231 span: decl.span,
232 block,
233 input,
234 exec_graph: self
235 .exec_graph
236 .drain(..)
237 .chain(once(ExecGraphNode::Ret))
238 .collect(),
239 }
240 }
241
242 fn lower_spec_decl_pat(&mut self, pat: &hir::Pat) -> PatId {
243 let id = self.assigner.next_pat();
244 let span = pat.span;
245 let ty = self.lower_ty(&pat.ty);
246
247 let kind = match &pat.kind {
248 hir::PatKind::Bind(ident) => fir::PatKind::Bind(self.lower_ident(ident)),
249 hir::PatKind::Discard => fir::PatKind::Discard,
250 hir::PatKind::Tuple(elems) => {
251 fir::PatKind::Tuple(elems.iter().map(|pat| self.lower_pat(pat)).collect())
252 }
253 hir::PatKind::Err => unreachable!("error pat should not be present"),
254 };
255
256 let pat = fir::Pat { id, span, ty, kind };
257 self.pats.insert(id, pat);
258 id
259 }
260
261 fn lower_block(&mut self, block: &hir::Block) -> BlockId {
262 let id = self.assigner.next_block();
263 let set_unit = block.stmts.is_empty()
264 || !matches!(
265 block.stmts.last().expect("block should be non-empty").kind,
266 hir::StmtKind::Expr(..)
267 );
268 let block = fir::Block {
269 id,
270 span: block.span,
271 ty: self.lower_ty(&block.ty),
272 stmts: block.stmts.iter().map(|s| self.lower_stmt(s)).collect(),
273 };
274 if set_unit {
275 self.exec_graph.push(ExecGraphNode::Unit);
276 }
277 self.blocks.insert(id, block);
278 id
279 }
280
281 fn lower_stmt(&mut self, stmt: &hir::Stmt) -> fir::StmtId {
282 let id = self.assigner.next_stmt();
283 let graph_start_idx = self.exec_graph.len();
284 self.exec_graph.push(ExecGraphNode::Stmt(id));
285 let kind = match &stmt.kind {
286 hir::StmtKind::Expr(expr) => fir::StmtKind::Expr(self.lower_expr(expr)),
287 hir::StmtKind::Item(item) => fir::StmtKind::Item(lower_local_item_id(*item)),
288 hir::StmtKind::Local(mutability, pat, expr) => {
289 let pat = self.lower_pat(pat);
290 let expr = self.lower_expr(expr);
291 self.exec_graph.push(ExecGraphNode::Bind(pat));
292 fir::StmtKind::Local(lower_mutability(*mutability), pat, expr)
293 }
294 hir::StmtKind::Qubit(_, _, _, _) => {
295 panic!("qubit statements should have been eliminated by passes");
296 }
297 hir::StmtKind::Semi(expr) => {
298 let expr = self.lower_expr(expr);
299 fir::StmtKind::Semi(expr)
300 }
301 };
302 let stmt = fir::Stmt {
303 id,
304 span: stmt.span,
305 kind,
306 exec_graph_range: graph_start_idx..self.exec_graph.len(),
307 };
308 self.stmts.insert(id, stmt);
309 id
310 }
311
312 #[allow(clippy::too_many_lines)]
313 fn lower_expr(&mut self, expr: &hir::Expr) -> ExprId {
314 let id = self.assigner.next_expr();
315 let graph_start_idx = self.exec_graph.len();
316 let ty = self.lower_ty(&expr.ty);
317
318 let kind = match &expr.kind {
319 hir::ExprKind::Array(items) => {
320 if items
321 .iter()
322 .all(|i| matches!(i.kind, hir::ExprKind::Lit(..)))
323 {
324 fir::ExprKind::ArrayLit(
325 items
326 .iter()
327 .map(|i| {
328 let i = self.lower_expr(i);
329 self.exec_graph.pop();
330 i
331 })
332 .collect(),
333 )
334 } else {
335 fir::ExprKind::Array(
336 items
337 .iter()
338 .map(|i| {
339 let i = self.lower_expr(i);
340 self.exec_graph.push(ExecGraphNode::Store);
341 i
342 })
343 .collect(),
344 )
345 }
346 }
347 hir::ExprKind::ArrayRepeat(value, size) => {
348 let value = self.lower_expr(value);
349 self.exec_graph.push(ExecGraphNode::Store);
350 let size = self.lower_expr(size);
351 fir::ExprKind::ArrayRepeat(value, size)
352 }
353 hir::ExprKind::Assign(lhs, rhs) => {
354 let idx = self.exec_graph.len();
355 let lhs = self.lower_expr(lhs);
356 // The left-hand side of an assigment is not really an expression to be executed,
357 // so remove any added nodes from the execution graph.
358 self.exec_graph.drain(idx..);
359 fir::ExprKind::Assign(lhs, self.lower_expr(rhs))
360 }
361 hir::ExprKind::AssignOp(op, lhs, rhs) => {
362 let idx = self.exec_graph.len();
363 let is_array = matches!(lhs.ty, qsc_hir::ty::Ty::Array(..));
364 let lhs = self.lower_expr(lhs);
365 if is_array {
366 // The left-hand side of an array append is not really an expression to be
367 // executed, so remove any added nodes from the execution graph.
368 self.exec_graph.drain(idx..);
369 }
370 let idx = self.exec_graph.len();
371 if matches!(op, hir::BinOp::AndL | hir::BinOp::OrL) {
372 // Put in a placeholder jump for what will be the short-circuit
373 self.exec_graph.push(ExecGraphNode::Jump(0));
374 } else if !is_array {
375 self.exec_graph.push(ExecGraphNode::Store);
376 }
377 let rhs = self.lower_expr(rhs);
378 match op {
379 hir::BinOp::AndL => {
380 self.exec_graph[idx] = ExecGraphNode::JumpIfNot(
381 self.exec_graph
382 .len()
383 .try_into()
384 .expect("nodes should fit into u32"),
385 );
386 }
387 hir::BinOp::OrL => {
388 self.exec_graph[idx] = ExecGraphNode::JumpIf(
389 self.exec_graph
390 .len()
391 .try_into()
392 .expect("nodes should fit into u32"),
393 );
394 }
395 _ => {}
396 }
397 fir::ExprKind::AssignOp(lower_binop(*op), lhs, rhs)
398 }
399 hir::ExprKind::AssignField(container, field, replace) => {
400 let field = lower_field(field);
401 let replace = self.lower_expr(replace);
402 self.exec_graph.push(ExecGraphNode::Store);
403 let container = self.lower_expr(container);
404 fir::ExprKind::AssignField(container, field, replace)
405 }
406 hir::ExprKind::AssignIndex(container, index, replace) => {
407 let index = self.lower_expr(index);
408 self.exec_graph.push(ExecGraphNode::Store);
409 let replace = self.lower_expr(replace);
410 let idx = self.exec_graph.len();
411 let container = self.lower_expr(container);
412 // The left-hand side of an array index assignment is not really an expression to be
413 // executed, so remove any added nodes from the exection graph.
414 self.exec_graph.drain(idx..);
415 fir::ExprKind::AssignIndex(container, index, replace)
416 }
417 hir::ExprKind::BinOp(op, lhs, rhs) => {
418 let lhs = self.lower_expr(lhs);
419 let idx = self.exec_graph.len();
420 if matches!(op, hir::BinOp::AndL | hir::BinOp::OrL) {
421 // Put in a placeholder jump for what will be the short-circuit
422 self.exec_graph.push(ExecGraphNode::Jump(0));
423 } else {
424 self.exec_graph.push(ExecGraphNode::Store);
425 }
426 let rhs = self.lower_expr(rhs);
427 match op {
428 // If the operator is logical AND, update the placeholder to skip the
429 // right-hand side if the left-hand side is false
430 hir::BinOp::AndL => {
431 self.exec_graph[idx] = ExecGraphNode::JumpIfNot(
432 self.exec_graph
433 .len()
434 .try_into()
435 .expect("nodes should fit into u32"),
436 );
437 }
438 // If the operator is logical OR, update the placeholder to skip the
439 // right-hand side if the left-hand side is true
440 hir::BinOp::OrL => {
441 self.exec_graph[idx] = ExecGraphNode::JumpIf(
442 self.exec_graph
443 .len()
444 .try_into()
445 .expect("nodes should fit into u32"),
446 );
447 }
448 _ => {}
449 }
450 fir::ExprKind::BinOp(lower_binop(*op), lhs, rhs)
451 }
452 hir::ExprKind::Block(block) => fir::ExprKind::Block(self.lower_block(block)),
453 hir::ExprKind::Call(callee, arg) => {
454 let call = self.lower_expr(callee);
455 self.exec_graph.push(ExecGraphNode::Store);
456 let arg = self.lower_expr(arg);
457 fir::ExprKind::Call(call, arg)
458 }
459 hir::ExprKind::Fail(message) => fir::ExprKind::Fail(self.lower_expr(message)),
460 hir::ExprKind::Field(container, field) => {
461 let container = self.lower_expr(container);
462 let field = lower_field(field);
463 fir::ExprKind::Field(container, field)
464 }
465 hir::ExprKind::If(cond, if_true, if_false) => {
466 let cond = self.lower_expr(cond);
467 let branch_idx = self.exec_graph.len();
468 // Put a placeholder in the execution graph for the jump past the true branch
469 self.exec_graph.push(ExecGraphNode::Jump(0));
470 let if_true = self.lower_expr(if_true);
471 let (if_false, else_idx) = if let Some(if_false) = if_false.as_ref() {
472 // Put a placeholder in the execution graph for the jump past the false branch
473 let idx = self.exec_graph.len();
474 self.exec_graph.push(ExecGraphNode::Jump(0));
475 let if_false = self.lower_expr(if_false);
476 // Update the placeholder to skip over the false branch
477 self.exec_graph[idx] = ExecGraphNode::Jump(
478 self.exec_graph
479 .len()
480 .try_into()
481 .expect("nodes should fit into u32"),
482 );
483 (Some(if_false), idx + 1)
484 } else {
485 // An if-expr without an else cannot return a value, so we need to
486 // insert a no-op to ensure a Unit value is returned for the expr.
487 let idx = self.exec_graph.len();
488 self.exec_graph.push(ExecGraphNode::Unit);
489 (None, idx)
490 };
491 // Update the placeholder to skip the true branch if the condition is false
492 self.exec_graph[branch_idx] = ExecGraphNode::JumpIfNot(
493 else_idx.try_into().expect("nodes should fit into u32"),
494 );
495 fir::ExprKind::If(cond, if_true, if_false)
496 }
497 hir::ExprKind::Index(container, index) => {
498 let container = self.lower_expr(container);
499 self.exec_graph.push(ExecGraphNode::Store);
500 let index = self.lower_expr(index);
501 fir::ExprKind::Index(container, index)
502 }
503 hir::ExprKind::Lit(lit) => lower_lit(lit),
504 hir::ExprKind::Range(start, step, end) => {
505 let start = start.as_ref().map(|s| self.lower_expr(s));
506 if start.is_some() {
507 self.exec_graph.push(ExecGraphNode::Store);
508 }
509 let step = step.as_ref().map(|s| self.lower_expr(s));
510 if step.is_some() {
511 self.exec_graph.push(ExecGraphNode::Store);
512 }
513 let end = end.as_ref().map(|e| self.lower_expr(e));
514 fir::ExprKind::Range(start, step, end)
515 }
516 hir::ExprKind::Return(expr) => {
517 let expr = self.lower_expr(expr);
518 self.exec_graph.push(ExecGraphNode::Ret);
519 fir::ExprKind::Return(expr)
520 }
521 hir::ExprKind::Tuple(items) => fir::ExprKind::Tuple(
522 items
523 .iter()
524 .map(|i| {
525 let i = self.lower_expr(i);
526 self.exec_graph.push(ExecGraphNode::Store);
527 i
528 })
529 .collect(),
530 ),
531 hir::ExprKind::UnOp(op, operand) => {
532 fir::ExprKind::UnOp(lower_unop(*op), self.lower_expr(operand))
533 }
534 hir::ExprKind::While(cond, body) => {
535 let cond_idx = self.exec_graph.len();
536 let cond = self.lower_expr(cond);
537 let idx = self.exec_graph.len();
538 // Put a placeholder in the execution graph for the jump past the loop
539 self.exec_graph.push(ExecGraphNode::Jump(0));
540 let body = self.lower_block(body);
541 self.exec_graph.push(ExecGraphNode::Jump(
542 cond_idx.try_into().expect("nodes should fit into u32"),
543 ));
544 // Update the placeholder to skip the loop if the condition is false
545 self.exec_graph[idx] = ExecGraphNode::JumpIfNot(
546 self.exec_graph
547 .len()
548 .try_into()
549 .expect("nodes should fit into u32"),
550 );
551 // While-exprs never have a return value, so we need to insert a no-op to ensure
552 // a Unit value is returned for the expr.
553 self.exec_graph.push(ExecGraphNode::Unit);
554 fir::ExprKind::While(cond, body)
555 }
556 hir::ExprKind::Closure(ids, id) => {
557 let ids = ids.iter().map(|id| self.lower_local_id(*id)).collect();
558 fir::ExprKind::Closure(ids, lower_local_item_id(*id))
559 }
560 hir::ExprKind::String(components) => fir::ExprKind::String(
561 components
562 .iter()
563 .map(|c| self.lower_string_component(c))
564 .collect(),
565 ),
566 hir::ExprKind::UpdateIndex(lhs, mid, rhs) => {
567 let mid = self.lower_expr(mid);
568 self.exec_graph.push(ExecGraphNode::Store);
569 let rhs = self.lower_expr(rhs);
570 self.exec_graph.push(ExecGraphNode::Store);
571 let lhs = self.lower_expr(lhs);
572 fir::ExprKind::UpdateIndex(lhs, mid, rhs)
573 }
574 hir::ExprKind::UpdateField(record, field, replace) => {
575 let field = lower_field(field);
576 let replace = self.lower_expr(replace);
577 self.exec_graph.push(ExecGraphNode::Store);
578 let record = self.lower_expr(record);
579 fir::ExprKind::UpdateField(record, field, replace)
580 }
581 hir::ExprKind::Var(res, args) => {
582 let res = self.lower_res(res);
583 let args = args.iter().map(|arg| self.lower_generic_arg(arg)).collect();
584 fir::ExprKind::Var(res, args)
585 }
586 hir::ExprKind::Conjugate(..) => panic!("conjugate should be eliminated by passes"),
587 hir::ExprKind::Err => panic!("error expr should not be present"),
588 hir::ExprKind::For(..) => panic!("for-loop should be eliminated by passes"),
589 hir::ExprKind::Hole => fir::ExprKind::Hole, // allowed for discards
590 hir::ExprKind::Repeat(..) => panic!("repeat-loop should be eliminated by passes"),
591 };
592
593 match kind {
594 // These expressions express specific control flow that is handled above.
595 fir::ExprKind::BinOp(fir::BinOp::AndL | fir::BinOp::OrL, _, _)
596 | fir::ExprKind::Block(..)
597 | fir::ExprKind::If(..)
598 | fir::ExprKind::Return(..)
599 | fir::ExprKind::While(..) => {}
600
601 // All other expressions should be added to the execution graph.
602 _ => self.exec_graph.push(ExecGraphNode::Expr(id)),
603 }
604
605 let expr = fir::Expr {
606 id,
607 span: expr.span,
608 ty,
609 kind,
610 exec_graph_range: graph_start_idx..self.exec_graph.len(),
611 };
612 self.exprs.insert(id, expr);
613 id
614 }
615
616 fn lower_string_component(&mut self, component: &hir::StringComponent) -> fir::StringComponent {
617 match component {
618 hir::StringComponent::Expr(expr) => {
619 let expr = self.lower_expr(expr);
620 self.exec_graph.push(ExecGraphNode::Store);
621 fir::StringComponent::Expr(expr)
622 }
623 hir::StringComponent::Lit(str) => fir::StringComponent::Lit(Rc::clone(str)),
624 }
625 }
626
627 fn lower_pat(&mut self, pat: &hir::Pat) -> PatId {
628 let id = self.assigner.next_pat();
629 let ty = self.lower_ty(&pat.ty);
630 let kind = match &pat.kind {
631 hir::PatKind::Bind(name) => {
632 let name = self.lower_ident(name);
633 fir::PatKind::Bind(name)
634 }
635 hir::PatKind::Discard => fir::PatKind::Discard,
636 hir::PatKind::Tuple(items) => {
637 fir::PatKind::Tuple(items.iter().map(|i| self.lower_pat(i)).collect())
638 }
639 hir::PatKind::Err => unreachable!("error pat should not be present"),
640 };
641
642 let pat = fir::Pat {
643 id,
644 span: pat.span,
645 ty,
646 kind,
647 };
648 self.pats.insert(id, pat);
649 id
650 }
651
652 fn lower_id(&mut self, id: hir::NodeId) -> fir::NodeId {
653 self.nodes.get(id).copied().unwrap_or_else(|| {
654 let new_id = self.assigner.next_node();
655 self.nodes.insert(id, new_id);
656 new_id
657 })
658 }
659
660 fn lower_local_id(&mut self, id: hir::NodeId) -> fir::LocalVarId {
661 self.locals.get(id).copied().unwrap_or_else(|| {
662 let new_id = self.assigner.next_local();
663 self.locals.insert(id, new_id);
664 new_id
665 })
666 }
667
668 fn lower_res(&mut self, res: &hir::Res) -> fir::Res {
669 match res {
670 hir::Res::Item(item) => fir::Res::Item(lower_item_id(item)),
671 hir::Res::Local(node) => fir::Res::Local(self.lower_local_id(*node)),
672 hir::Res::Err => fir::Res::Err,
673 }
674 }
675
676 fn lower_ident(&mut self, ident: &hir::Ident) -> fir::Ident {
677 fir::Ident {
678 id: self.lower_local_id(ident.id),
679 span: ident.span,
680 name: ident.name.clone(),
681 }
682 }
683
684 fn lower_udt(&mut self, udt: &qsc_hir::ty::Udt) -> qsc_fir::ty::Udt {
685 let span = udt.span;
686 let name = udt.name.clone();
687 let definition = self.lower_udt_defn(&udt.definition);
688 qsc_fir::ty::Udt {
689 span,
690 name,
691 definition,
692 }
693 }
694
695 fn lower_generic_arg(&mut self, arg: &qsc_hir::ty::GenericArg) -> qsc_fir::ty::GenericArg {
696 match &arg {
697 qsc_hir::ty::GenericArg::Ty(ty) => qsc_fir::ty::GenericArg::Ty(self.lower_ty(ty)),
698 qsc_hir::ty::GenericArg::Functor(functors) => {
699 qsc_fir::ty::GenericArg::Functor(lower_functor_set(functors))
700 }
701 }
702 }
703
704 fn lower_udt_defn(&mut self, definition: &qsc_hir::ty::UdtDef) -> qsc_fir::ty::UdtDef {
705 let span = definition.span;
706 let kind = match &definition.kind {
707 qsc_hir::ty::UdtDefKind::Field(field) => {
708 qsc_fir::ty::UdtDefKind::Field(self.lower_udt_field(field))
709 }
710 qsc_hir::ty::UdtDefKind::Tuple(tup) => qsc_fir::ty::UdtDefKind::Tuple(
711 tup.iter().map(|def| self.lower_udt_defn(def)).collect(),
712 ),
713 };
714 qsc_fir::ty::UdtDef { span, kind }
715 }
716
717 fn lower_arrow(&mut self, arrow: &qsc_hir::ty::Arrow) -> Arrow {
718 Arrow {
719 kind: lower_callable_kind(arrow.kind),
720 input: Box::new(self.lower_ty(&arrow.input)),
721 output: Box::new(self.lower_ty(&arrow.output)),
722 functors: lower_functor_set(&arrow.functors),
723 }
724 }
725
726 fn lower_ty(&mut self, ty: &qsc_hir::ty::Ty) -> Ty {
727 match ty {
728 qsc_hir::ty::Ty::Array(array) => qsc_fir::ty::Ty::Array(Box::new(self.lower_ty(array))),
729 qsc_hir::ty::Ty::Arrow(arrow) => {
730 qsc_fir::ty::Ty::Arrow(Box::new(self.lower_arrow(arrow)))
731 }
732 qsc_hir::ty::Ty::Infer(id) => {
733 qsc_fir::ty::Ty::Infer(qsc_fir::ty::InferTyId::from(usize::from(*id)))
734 }
735 qsc_hir::ty::Ty::Param(_, id) => {
736 qsc_fir::ty::Ty::Param(qsc_fir::ty::ParamId::from(usize::from(*id)))
737 }
738 qsc_hir::ty::Ty::Prim(prim) => qsc_fir::ty::Ty::Prim(lower_ty_prim(*prim)),
739 qsc_hir::ty::Ty::Tuple(tys) => {
740 qsc_fir::ty::Ty::Tuple(tys.iter().map(|ty| self.lower_ty(ty)).collect())
741 }
742 qsc_hir::ty::Ty::Udt(_, res) => qsc_fir::ty::Ty::Udt(self.lower_res(res)),
743 qsc_hir::ty::Ty::Err => qsc_fir::ty::Ty::Err,
744 }
745 }
746
747 fn lower_udt_field(&mut self, field: &qsc_hir::ty::UdtField) -> qsc_fir::ty::UdtField {
748 qsc_fir::ty::UdtField {
749 ty: self.lower_ty(&field.ty),
750 name: field.name.clone(),
751 name_span: field.name_span,
752 }
753 }
754}
755
756fn lower_generics(generics: &[qsc_hir::ty::GenericParam]) -> Vec<qsc_fir::ty::GenericParam> {
757 generics.iter().map(lower_generic_param).collect()
758}
759
760fn lower_attrs(attrs: &[hir::Attr]) -> Vec<fir::Attr> {
761 attrs.iter().map(|_| fir::Attr::EntryPoint).collect()
762}
763
764fn lower_functors(functors: qsc_hir::ty::FunctorSetValue) -> qsc_fir::ty::FunctorSetValue {
765 lower_functor_set_value(functors)
766}
767
768fn lower_generic_param(g: &qsc_hir::ty::GenericParam) -> qsc_fir::ty::GenericParam {
769 match g {
770 qsc_hir::ty::GenericParam::Ty(_) => qsc_fir::ty::GenericParam::Ty,
771 qsc_hir::ty::GenericParam::Functor(value) => {
772 qsc_fir::ty::GenericParam::Functor(lower_functor_set_value(*value))
773 }
774 }
775}
776
777fn lower_field(field: &hir::Field) -> fir::Field {
778 match field {
779 hir::Field::Err => fir::Field::Err,
780 hir::Field::Path(path) => fir::Field::Path(fir::FieldPath {
781 indices: path.indices.clone(),
782 }),
783 hir::Field::Prim(field) => fir::Field::Prim(lower_prim_field(*field)),
784 }
785}
786
787fn lower_functor_set(functors: &qsc_hir::ty::FunctorSet) -> qsc_fir::ty::FunctorSet {
788 match *functors {
789 qsc_hir::ty::FunctorSet::Value(v) => {
790 qsc_fir::ty::FunctorSet::Value(lower_functor_set_value(v))
791 }
792 qsc_hir::ty::FunctorSet::Param(p, _) => {
793 qsc_fir::ty::FunctorSet::Param(ParamId::from(usize::from(p)))
794 }
795 qsc_hir::ty::FunctorSet::Infer(i) => {
796 qsc_fir::ty::FunctorSet::Infer(InferFunctorId::from(usize::from(i)))
797 }
798 }
799}
800
801fn lower_prim_field(field: hir::PrimField) -> fir::PrimField {
802 match field {
803 hir::PrimField::Start => fir::PrimField::Start,
804 hir::PrimField::Step => fir::PrimField::Step,
805 hir::PrimField::End => fir::PrimField::End,
806 }
807}
808
809fn lower_item_id(id: &hir::ItemId) -> fir::ItemId {
810 fir::ItemId {
811 item: lower_local_item_id(id.item),
812 package: id.package.map(|p| fir::PackageId::from(usize::from(p))),
813 }
814}
815
816fn lower_ty_prim(prim: qsc_hir::ty::Prim) -> qsc_fir::ty::Prim {
817 match prim {
818 qsc_hir::ty::Prim::Bool => qsc_fir::ty::Prim::Bool,
819 qsc_hir::ty::Prim::Double => qsc_fir::ty::Prim::Double,
820 qsc_hir::ty::Prim::Int => qsc_fir::ty::Prim::Int,
821 qsc_hir::ty::Prim::Qubit => qsc_fir::ty::Prim::Qubit,
822 qsc_hir::ty::Prim::Result => qsc_fir::ty::Prim::Result,
823 qsc_hir::ty::Prim::String => qsc_fir::ty::Prim::String,
824 qsc_hir::ty::Prim::BigInt => qsc_fir::ty::Prim::BigInt,
825 qsc_hir::ty::Prim::RangeTo => qsc_fir::ty::Prim::RangeTo,
826 qsc_hir::ty::Prim::RangeFrom => qsc_fir::ty::Prim::RangeFrom,
827 qsc_hir::ty::Prim::Pauli => qsc_fir::ty::Prim::Pauli,
828 qsc_hir::ty::Prim::RangeFull => qsc_fir::ty::Prim::RangeFull,
829 qsc_hir::ty::Prim::Range => qsc_fir::ty::Prim::Range,
830 }
831}
832
833fn lower_visibility(visibility: hir::Visibility) -> fir::Visibility {
834 match visibility {
835 hir::Visibility::Public => fir::Visibility::Public,
836 hir::Visibility::Internal => fir::Visibility::Internal,
837 }
838}
839
840fn lower_callable_kind(kind: hir::CallableKind) -> fir::CallableKind {
841 match kind {
842 hir::CallableKind::Function => fir::CallableKind::Function,
843 hir::CallableKind::Operation => fir::CallableKind::Operation,
844 }
845}
846
847fn lower_mutability(mutability: hir::Mutability) -> fir::Mutability {
848 match mutability {
849 hir::Mutability::Immutable => fir::Mutability::Immutable,
850 hir::Mutability::Mutable => fir::Mutability::Mutable,
851 }
852}
853
854fn lower_unop(op: hir::UnOp) -> fir::UnOp {
855 match op {
856 hir::UnOp::Functor(f) => fir::UnOp::Functor(lower_functor(f)),
857 hir::UnOp::Neg => fir::UnOp::Neg,
858 hir::UnOp::NotB => fir::UnOp::NotB,
859 hir::UnOp::NotL => fir::UnOp::NotL,
860 hir::UnOp::Pos => fir::UnOp::Pos,
861 hir::UnOp::Unwrap => fir::UnOp::Unwrap,
862 }
863}
864
865fn lower_binop(op: hir::BinOp) -> fir::BinOp {
866 match op {
867 hir::BinOp::Add => fir::BinOp::Add,
868 hir::BinOp::AndB => fir::BinOp::AndB,
869 hir::BinOp::AndL => fir::BinOp::AndL,
870 hir::BinOp::Div => fir::BinOp::Div,
871 hir::BinOp::Eq => fir::BinOp::Eq,
872 hir::BinOp::Exp => fir::BinOp::Exp,
873 hir::BinOp::Gt => fir::BinOp::Gt,
874 hir::BinOp::Gte => fir::BinOp::Gte,
875 hir::BinOp::Lt => fir::BinOp::Lt,
876 hir::BinOp::Lte => fir::BinOp::Lte,
877 hir::BinOp::Mod => fir::BinOp::Mod,
878 hir::BinOp::Mul => fir::BinOp::Mul,
879 hir::BinOp::Neq => fir::BinOp::Neq,
880 hir::BinOp::OrB => fir::BinOp::OrB,
881 hir::BinOp::OrL => fir::BinOp::OrL,
882 hir::BinOp::Shl => fir::BinOp::Shl,
883 hir::BinOp::Shr => fir::BinOp::Shr,
884 hir::BinOp::Sub => fir::BinOp::Sub,
885 hir::BinOp::XorB => fir::BinOp::XorB,
886 }
887}
888
889fn lower_lit(lit: &hir::Lit) -> fir::ExprKind {
890 match lit {
891 hir::Lit::BigInt(value) => fir::ExprKind::Lit(fir::Lit::BigInt(value.clone())),
892 &hir::Lit::Bool(value) => fir::ExprKind::Lit(fir::Lit::Bool(value)),
893 &hir::Lit::Double(value) => fir::ExprKind::Lit(fir::Lit::Double(value)),
894 &hir::Lit::Int(value) => fir::ExprKind::Lit(fir::Lit::Int(value)),
895 hir::Lit::Pauli(hir::Pauli::I) => fir::ExprKind::Lit(fir::Lit::Pauli(fir::Pauli::I)),
896 hir::Lit::Pauli(hir::Pauli::X) => fir::ExprKind::Lit(fir::Lit::Pauli(fir::Pauli::X)),
897 hir::Lit::Pauli(hir::Pauli::Y) => fir::ExprKind::Lit(fir::Lit::Pauli(fir::Pauli::Y)),
898 hir::Lit::Pauli(hir::Pauli::Z) => fir::ExprKind::Lit(fir::Lit::Pauli(fir::Pauli::Z)),
899 hir::Lit::Result(hir::Result::One) => {
900 fir::ExprKind::Lit(fir::Lit::Result(fir::Result::One))
901 }
902 hir::Lit::Result(hir::Result::Zero) => {
903 fir::ExprKind::Lit(fir::Lit::Result(fir::Result::Zero))
904 }
905 }
906}
907
908fn lower_functor(functor: hir::Functor) -> fir::Functor {
909 match functor {
910 hir::Functor::Adj => fir::Functor::Adj,
911 hir::Functor::Ctl => fir::Functor::Ctl,
912 }
913}
914
915fn lower_functor_set_value(value: qsc_hir::ty::FunctorSetValue) -> qsc_fir::ty::FunctorSetValue {
916 match value {
917 qsc_hir::ty::FunctorSetValue::Empty => qsc_fir::ty::FunctorSetValue::Empty,
918 qsc_hir::ty::FunctorSetValue::Adj => qsc_fir::ty::FunctorSetValue::Adj,
919 qsc_hir::ty::FunctorSetValue::Ctl => qsc_fir::ty::FunctorSetValue::Ctl,
920 qsc_hir::ty::FunctorSetValue::CtlAdj => qsc_fir::ty::FunctorSetValue::CtlAdj,
921 }
922}
923
924#[must_use]
925fn lower_local_item_id(id: qsc_hir::hir::LocalItemId) -> LocalItemId {
926 LocalItemId::from(usize::from(id))
927}
928