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

1283lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#[cfg(test)]
5mod tests;
6
7use crate::{
8 closure::{self, Lambda, PartialApp},
9 resolve::{self, Names, iter_valid_items},
10 typeck::{
11 self,
12 convert::{self, synthesize_functor_params},
13 },
14};
15use miette::Diagnostic;
16use qsc_ast::ast::{self, FieldAccess, Ident, Idents, PathKind};
17use qsc_data_structures::{
18 index_map::IndexMap,
19 span::Span,
20 target::{Profile, TargetCapabilityFlags},
21};
22use qsc_hir::{
23 assigner::Assigner,
24 hir::{self, ItemId, LocalItemId, PackageId, Res, Visibility},
25 mut_visit::MutVisitor,
26 ty::{Arrow, FunctorSetValue, GenericArg, ParamId, Ty, TypeParameter},
27};
28use std::{
29 clone::Clone,
30 iter::{once, repeat},
31 rc::Rc,
32 str::FromStr,
33 vec,
34};
35use thiserror::Error;
36
37use self::convert::TyConversionError;
38
39#[derive(Clone, Debug, Diagnostic, Error)]
40pub(super) enum Error {
41 #[error("unknown attribute {0}")]
42 #[diagnostic(help(
43 "supported attributes are: EntryPoint, Config, SimulatableIntrinsic, Measurement, Reset"
44 ))]
45 #[diagnostic(code("Qsc.LowerAst.UnknownAttr"))]
46 UnknownAttr(String, #[label] Span),
47 #[error("invalid attribute arguments: expected {0}")]
48 #[diagnostic(code("Qsc.LowerAst.InvalidAttrArgs"))]
49 InvalidAttrArgs(String, #[label] Span),
50 #[error("invalid use of the {0} attribute on a function")]
51 #[diagnostic(help("try declaring the callable as an operation"))]
52 #[diagnostic(code("Qsc.LowerAst.InvalidAttrOnFunction"))]
53 InvalidAttrOnFunction(String, #[label] Span),
54 #[error("missing callable body")]
55 #[diagnostic(code("Qsc.LowerAst.MissingBody"))]
56 MissingBody(#[label] Span),
57 #[error("duplicate specialization")]
58 #[diagnostic(code("Qsc.LowerAst.DuplicateSpec"))]
59 DuplicateSpec(#[label] Span),
60 #[error("invalid use of elided pattern")]
61 #[diagnostic(code("Qsc.LowerAst.InvalidElidedPat"))]
62 InvalidElidedPat(#[label] Span),
63 #[error("invalid pattern for specialization declaration")]
64 #[diagnostic(code("Qsc.LowerAst.InvalidSpecPat"))]
65 InvalidSpecPat(#[label] Span),
66 #[error("missing type in item signature")]
67 #[diagnostic(help("a type must be provided for this item"))]
68 #[diagnostic(code("Qsc.LowerAst.MissingTy"))]
69 MissingTy {
70 #[label]
71 span: Span,
72 },
73 #[error("unrecognized class constraint {name}")]
74 #[help(
75 "supported classes are Eq, Add, Sub, Mul, Div, Mod, Signed, Ord, Exp, Integral, and Show"
76 )]
77 #[diagnostic(code("Qsc.LowerAst.UnrecognizedClass"))]
78 UnrecognizedClass {
79 #[label]
80 span: Span,
81 name: String,
82 },
83 #[error("class constraint is recursive via {name}")]
84 #[help(
85 "if a type refers to itself via its constraints, it is self-referential and cannot ever be resolved"
86 )]
87 #[diagnostic(code("Qsc.LowerAst.RecursiveClassConstraint"))]
88 RecursiveClassConstraint {
89 #[label]
90 span: Span,
91 name: String,
92 },
93 #[error("expected {expected} parameters for constraint, found {found}")]
94 #[diagnostic(code("Qsc.TypeCk.IncorrectNumberOfConstraintParameters"))]
95 IncorrectNumberOfConstraintParameters {
96 expected: usize,
97 found: usize,
98 #[label]
99 span: Span,
100 },
101 #[error("namespace cannot be exported since it is a parent namespace")]
102 #[diagnostic(code("Qsc.LowerAst.ParentNamespaceExport"))]
103 #[diagnostic(help(
104 "to make this namespace exportable, consider explicitly declaring it in source: `namespace Foo {{ ... }}`"
105 ))]
106 ParentNamespaceExport {
107 #[label]
108 span: Span,
109 },
110 #[error("reexporting a namespace from another package is not supported")]
111 #[diagnostic(help("consider reexporting items individually"))]
112 #[diagnostic(code("Qsc.LowerAst.CrossPackageNamespaceReexport"))]
113 CrossPackageNamespaceReexport(#[label] Span),
114}
115
116impl From<TyConversionError> for Error {
117 fn from(err: TyConversionError) -> Self {
118 use TyConversionError::*;
119 match err {
120 MissingTy { span } => Error::MissingTy { span },
121 UnrecognizedClass { span, name } => Error::UnrecognizedClass { span, name },
122 RecursiveClassConstraint { span, name } => {
123 Error::RecursiveClassConstraint { span, name }
124 }
125 IncorrectNumberOfConstraintParameters {
126 expected,
127 found,
128 span,
129 } => Error::IncorrectNumberOfConstraintParameters {
130 expected,
131 found,
132 span,
133 },
134 }
135 }
136}
137
138pub(super) struct Lowerer {
139 package_id: PackageId,
140 nodes: IndexMap<ast::NodeId, hir::NodeId>,
141 locals: IndexMap<hir::NodeId, (hir::Ident, Ty)>,
142 parent: Option<LocalItemId>,
143 items: Vec<hir::Item>,
144 errors: Vec<Error>,
145}
146
147impl Lowerer {
148 pub(super) fn new(package_id: PackageId) -> Self {
149 Self {
150 package_id,
151 nodes: IndexMap::new(),
152 locals: IndexMap::new(),
153 parent: None,
154 items: Vec::new(),
155 errors: Vec::new(),
156 }
157 }
158
159 pub(super) fn clear_items(&mut self) {
160 self.items.clear();
161 }
162
163 pub(super) fn drain_errors(&mut self) -> vec::Drain<'_, Error> {
164 self.errors.drain(..)
165 }
166
167 pub(super) fn with<'a>(
168 &'a mut self,
169 assigner: &'a mut Assigner,
170 names: &'a Names,
171 tys: &'a typeck::Table,
172 ) -> With<'a> {
173 With {
174 lowerer: self,
175 assigner,
176 names,
177 tys,
178 }
179 }
180}
181
182pub(super) struct With<'a> {
183 lowerer: &'a mut Lowerer,
184 assigner: &'a mut Assigner,
185 names: &'a Names,
186 tys: &'a typeck::Table,
187}
188
189impl With<'_> {
190 pub(super) fn lower_package(&mut self, package: &ast::Package) -> hir::Package {
191 let mut stmts = Vec::new();
192 for node in &package.nodes {
193 match node {
194 ast::TopLevelNode::Namespace(namespace) => self.lower_namespace(namespace),
195 ast::TopLevelNode::Stmt(stmt) => {
196 stmts.extend(self.lower_stmt(stmt));
197 }
198 }
199 }
200
201 let entry = package.entry.as_ref().map(|e| self.lower_expr(e));
202
203 let mut items = self
204 .lowerer
205 .items
206 .drain(..)
207 .map(|i| (i.id, i))
208 .collect::<IndexMap<_, _>>();
209
210 collapse_self_exports(&mut items, self.lowerer.package_id);
211
212 hir::Package {
213 package_id: self.lowerer.package_id,
214 items,
215 stmts,
216 entry,
217 }
218 }
219
220 pub(super) fn lower_namespace(&mut self, namespace: &ast::Namespace) {
221 let Some(&resolve::Res::Item(hir::ItemId { item: id, .. }, _)) = self.names.get(
222 namespace
223 .name
224 .last()
225 .expect("namespace name should contain at least one ident")
226 .id,
227 ) else {
228 panic!("namespace should have item ID");
229 };
230
231 self.lowerer.parent = Some(id);
232
233 let items = namespace
234 .items
235 .iter()
236 .flat_map(|i| self.lower_item(i))
237 .collect::<Vec<_>>();
238
239 let name = self.lower_idents(&namespace.name);
240
241 self.lowerer.items.push(hir::Item {
242 id,
243 span: namespace.span,
244 parent: None,
245 doc: Rc::clone(&namespace.doc),
246 attrs: Vec::new(),
247 visibility: hir::Visibility::Public,
248 kind: hir::ItemKind::Namespace(name, items),
249 });
250
251 self.lowerer.parent = None;
252 }
253
254 fn lower_item(&mut self, item: &ast::Item) -> Vec<LocalItemId> {
255 let attrs: Vec<_> = item
256 .attrs
257 .iter()
258 .filter_map(|a| self.lower_attr(a))
259 .collect();
260
261 let resolve_id = |id| match self.names.get(id) {
262 Some(&resolve::Res::Item(item, _)) => item,
263 _ => panic!("item should have item ID"),
264 };
265
266 let mut items = Vec::new();
267 match &*item.kind {
268 ast::ItemKind::Err | ast::ItemKind::Open(..) => {}
269 ast::ItemKind::ImportOrExport(decl) if decl.is_import() => {}
270 ast::ItemKind::ImportOrExport(decl) => {
271 // Only exports are handled here, imports vanish in the HIR
272 for item in iter_valid_items(decl) {
273 let id = resolve_id(item.name().id);
274 let res = self.path_to_res(item.path);
275 let name = self.lower_ident(item.name());
276 items.push((id, hir::ItemKind::Export(name, res), Visibility::Public));
277 }
278 }
279 ast::ItemKind::Callable(callable) => {
280 let id = resolve_id(callable.name.id);
281 let grandparent = self.lowerer.parent;
282 self.lowerer.parent = Some(id.item);
283 let (callable, errs) = self.lower_callable_decl(callable, &attrs);
284 self.lowerer.errors.extend(
285 errs.into_iter().map(|err| {
286 Into::<Error>::into(Into::<convert::TyConversionError>::into(err))
287 }),
288 );
289 self.lowerer.parent = grandparent;
290 items.push((
291 id,
292 hir::ItemKind::Callable(callable.into()),
293 Visibility::Internal,
294 ));
295 }
296 ast::ItemKind::Ty(name, _) => {
297 let id = resolve_id(name.id);
298 let udt = self
299 .tys
300 .udts
301 .get(&id)
302 .expect("type item should have lowered UDT");
303
304 items.push((
305 id,
306 hir::ItemKind::Ty(self.lower_ident(name), udt.clone()),
307 Visibility::Internal,
308 ));
309 }
310 ast::ItemKind::Struct(decl) => {
311 let id = resolve_id(decl.name.id);
312 let strct = self
313 .tys
314 .udts
315 .get(&id)
316 .expect("type item should have lowered struct");
317
318 items.push((
319 id,
320 hir::ItemKind::Ty(self.lower_ident(&decl.name), strct.clone()),
321 Visibility::Internal,
322 ));
323 }
324 }
325
326 let ids = items.iter().map(|(id, _, _)| id.item).collect::<Vec<_>>();
327
328 self.lowerer.items.extend(
329 items
330 .into_iter()
331 .zip(once(attrs).chain(repeat(Vec::new()))) // only apply the attrs to the first item
332 .map(|((id, kind, visibility), attrs)| hir::Item {
333 id: id.item,
334 span: item.span,
335 parent: self.lowerer.parent,
336 doc: Rc::clone(&item.doc),
337 attrs,
338 visibility,
339 kind,
340 }),
341 );
342
343 ids
344 }
345
346 fn lower_attr(&mut self, attr: &ast::Attr) -> Option<hir::Attr> {
347 match hir::Attr::from_str(attr.name.name.as_ref()) {
348 Ok(hir::Attr::EntryPoint) => match &*attr.arg.kind {
349 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::EntryPoint),
350 // @EntryPoint(Profile)
351 ast::ExprKind::Paren(inner)
352 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
353 if Profile::from_str(path.name.name.as_ref()).is_ok()) =>
354 {
355 Some(hir::Attr::EntryPoint)
356 }
357 // Any other form is not valid so generates an error.
358 _ => {
359 self.lowerer.errors.push(Error::InvalidAttrArgs(
360 "empty or profile name".to_string(),
361 attr.arg.span,
362 ));
363 None
364 }
365 },
366 Ok(hir::Attr::Unimplemented) => match &*attr.arg.kind {
367 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Unimplemented),
368 _ => {
369 self.lowerer
370 .errors
371 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
372 None
373 }
374 },
375 Ok(hir::Attr::Config) => {
376 match &*attr.arg.kind {
377 // @Config(Capability)
378 ast::ExprKind::Paren(inner)
379 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
380 if TargetCapabilityFlags::from_str(path.name.name.as_ref()).is_ok()) => {}
381
382 // @Config(not Capability)
383 ast::ExprKind::Paren(inner)
384 if matches!(inner.kind.as_ref(), ast::ExprKind::UnOp(ast::UnOp::NotL, inner)
385 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
386 if TargetCapabilityFlags::from_str(path.as_ref().name.name.as_ref()).is_ok())) =>
387 {}
388
389 // Any other form is not valid so generates an error.
390 _ => {
391 self.lowerer.errors.push(Error::InvalidAttrArgs(
392 "runtime capability".to_string(),
393 attr.arg.span,
394 ));
395 }
396 }
397 None
398 }
399 Ok(hir::Attr::SimulatableIntrinsic) => match &*attr.arg.kind {
400 ast::ExprKind::Tuple(args) if args.is_empty() => {
401 Some(hir::Attr::SimulatableIntrinsic)
402 }
403 _ => {
404 self.lowerer
405 .errors
406 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
407 None
408 }
409 },
410 Ok(hir::Attr::Measurement) => match &*attr.arg.kind {
411 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Measurement),
412 _ => {
413 self.lowerer
414 .errors
415 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
416 None
417 }
418 },
419 Ok(hir::Attr::Reset) => match &*attr.arg.kind {
420 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Reset),
421 _ => {
422 self.lowerer
423 .errors
424 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
425 None
426 }
427 },
428 Ok(hir::Attr::Test) => {
429 // verify that no args are passed to the attribute
430 match &*attr.arg.kind {
431 ast::ExprKind::Tuple(args) if args.is_empty() => {}
432 _ => {
433 self.lowerer
434 .errors
435 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
436 }
437 }
438 // lower the attribute even if it has invalid args
439 Some(hir::Attr::Test)
440 }
441 Err(()) => {
442 self.lowerer.errors.push(Error::UnknownAttr(
443 attr.name.name.to_string(),
444 attr.name.span,
445 ));
446 None
447 }
448 }
449 }
450
451 /// Generates generic parameters for the functors, if there were generics on the original callable.
452 /// Basically just creates new generic params for the purpose of being used in functor callable
453 /// decls.
454 pub(crate) fn synthesize_callable_generics(
455 &mut self,
456 generics: &[ast::TypeParameter],
457 input: &mut hir::Pat,
458 ) -> (Vec<qsc_hir::ty::TypeParameter>, Vec<TyConversionError>) {
459 let (mut params, errs) = convert::type_parameters_for_ast_callable(self.names, generics);
460 let mut functor_params =
461 Self::synthesize_functor_params_in_pat(&mut params.len().into(), input);
462 params.append(&mut functor_params);
463 (params, errs)
464 }
465
466 fn synthesize_functor_params_in_pat(
467 next_param: &mut ParamId,
468 pat: &mut hir::Pat,
469 ) -> Vec<TypeParameter> {
470 match &mut pat.kind {
471 hir::PatKind::Discard | hir::PatKind::Err | hir::PatKind::Bind(_) => {
472 synthesize_functor_params(next_param, &mut pat.ty)
473 }
474 hir::PatKind::Tuple(items) => {
475 let mut params = Vec::new();
476 for item in &mut *items {
477 params.append(&mut Self::synthesize_functor_params_in_pat(
478 next_param, item,
479 ));
480 }
481 if !params.is_empty() {
482 pat.ty = Ty::Tuple(items.iter().map(|i| i.ty.clone()).collect());
483 }
484 params
485 }
486 }
487 }
488
489 pub(super) fn lower_callable_decl(
490 &mut self,
491 decl: &ast::CallableDecl,
492 attrs: &[qsc_hir::hir::Attr],
493 ) -> (hir::CallableDecl, Vec<TyConversionError>) {
494 let id = self.lower_id(decl.id);
495 let kind = self.lower_callable_kind(decl.kind, attrs, decl.name.span);
496 let name = self.lower_ident(&decl.name);
497 let mut input = self.lower_pat(&decl.input);
498 let output = convert::ty_from_ast(self.names, &decl.output, &mut Default::default()).0;
499 let (generics, errs) = self.synthesize_callable_generics(&decl.generics, &mut input);
500 let functors = convert::ast_callable_functors(decl);
501
502 let (body, adj, ctl, ctl_adj) = match decl.body.as_ref() {
503 ast::CallableBody::Block(block) => {
504 let body = hir::SpecDecl {
505 id: self.assigner.next_node(),
506 span: decl.span,
507 body: hir::SpecBody::Impl(None, self.lower_block(block)),
508 };
509 (body, None, None, None)
510 }
511 ast::CallableBody::Specs(specs) => {
512 let body = self.find_spec(specs, ast::Spec::Body).unwrap_or_else(|| {
513 self.lowerer.errors.push(Error::MissingBody(decl.span));
514 hir::SpecDecl {
515 id: self.assigner.next_node(),
516 span: decl.span,
517 body: hir::SpecBody::Gen(hir::SpecGen::Auto),
518 }
519 });
520 let adj = self.find_spec(specs, ast::Spec::Adj);
521 let ctl = self.find_spec(specs, ast::Spec::Ctl);
522 let ctl_adj = self.find_spec(specs, ast::Spec::CtlAdj);
523 (body, adj, ctl, ctl_adj)
524 }
525 };
526
527 (
528 hir::CallableDecl {
529 id,
530 span: decl.span,
531 kind,
532 name,
533 generics,
534 input,
535 output,
536 functors,
537 body,
538 adj,
539 ctl,
540 ctl_adj,
541 attrs: attrs.to_vec(),
542 },
543 errs,
544 )
545 }
546
547 fn check_invalid_attrs_on_function(&mut self, attrs: &[hir::Attr], span: Span) {
548 const INVALID_ATTRS: [hir::Attr; 2] = [hir::Attr::Measurement, hir::Attr::Reset];
549
550 for invalid_attr in &INVALID_ATTRS {
551 if attrs.contains(invalid_attr) {
552 self.lowerer.errors.push(Error::InvalidAttrOnFunction(
553 format!("{invalid_attr:?}"),
554 span,
555 ));
556 }
557 }
558 }
559
560 fn lower_callable_kind(
561 &mut self,
562 kind: ast::CallableKind,
563 attrs: &[hir::Attr],
564 span: Span,
565 ) -> hir::CallableKind {
566 match kind {
567 ast::CallableKind::Function => {
568 self.check_invalid_attrs_on_function(attrs, span);
569 hir::CallableKind::Function
570 }
571 ast::CallableKind::Operation => hir::CallableKind::Operation,
572 }
573 }
574
575 fn find_spec(
576 &mut self,
577 specs: &[Box<ast::SpecDecl>],
578 spec: ast::Spec,
579 ) -> Option<hir::SpecDecl> {
580 match specs
581 .iter()
582 .filter(|s| s.spec == spec)
583 .collect::<Vec<_>>()
584 .as_slice()
585 {
586 [] => None,
587 [single] => Some(self.lower_spec_decl(single)),
588 dupes => {
589 for dup in dupes {
590 self.lowerer.errors.push(Error::DuplicateSpec(dup.span));
591 }
592 Some(self.lower_spec_decl(dupes[0]))
593 }
594 }
595 }
596
597 fn lower_spec_decl(&mut self, decl: &ast::SpecDecl) -> hir::SpecDecl {
598 hir::SpecDecl {
599 id: self.lower_id(decl.id),
600 span: decl.span,
601 body: match &decl.body {
602 ast::SpecBody::Gen(spec_gen) => hir::SpecBody::Gen(match spec_gen {
603 ast::SpecGen::Auto => hir::SpecGen::Auto,
604 ast::SpecGen::Distribute => hir::SpecGen::Distribute,
605 ast::SpecGen::Intrinsic => hir::SpecGen::Intrinsic,
606 ast::SpecGen::Invert => hir::SpecGen::Invert,
607 ast::SpecGen::Slf => hir::SpecGen::Slf,
608 }),
609 ast::SpecBody::Impl(input, block) => {
610 hir::SpecBody::Impl(self.lower_spec_decl_pat(input), self.lower_block(block))
611 }
612 },
613 }
614 }
615
616 fn lower_spec_decl_pat(&mut self, pat: &ast::Pat) -> Option<hir::Pat> {
617 if let ast::PatKind::Paren(inner) = &*pat.kind {
618 return self.lower_spec_decl_pat(inner);
619 }
620
621 match &*pat.kind {
622 ast::PatKind::Elided => return None,
623 ast::PatKind::Tuple(items)
624 if items.len() == 2 && *items[1].kind == ast::PatKind::Elided =>
625 {
626 return Some(self.lower_pat(&items[0]));
627 }
628 _ => self.lowerer.errors.push(Error::InvalidSpecPat(pat.span)),
629 }
630
631 None
632 }
633
634 fn lower_block(&mut self, block: &ast::Block) -> hir::Block {
635 hir::Block {
636 id: self.lower_id(block.id),
637 span: block.span,
638 ty: self.tys.terms.get(block.id).map_or(Ty::Err, Clone::clone),
639 stmts: block
640 .stmts
641 .iter()
642 .flat_map(|s| self.lower_stmt(s))
643 .collect(),
644 }
645 }
646
647 pub(super) fn lower_stmt(&mut self, stmt: &ast::Stmt) -> Vec<hir::Stmt> {
648 let id = self.lower_id(stmt.id);
649 let mut stmts = Vec::new();
650 match &*stmt.kind {
651 ast::StmtKind::Empty | ast::StmtKind::Err => {}
652 ast::StmtKind::Expr(expr) => stmts.push(hir::StmtKind::Expr(self.lower_expr(expr))),
653 ast::StmtKind::Item(item) => {
654 stmts.extend(self.lower_item(item).into_iter().map(hir::StmtKind::Item));
655 }
656 ast::StmtKind::Local(mutability, lhs, rhs) => stmts.push(hir::StmtKind::Local(
657 lower_mutability(*mutability),
658 self.lower_pat(lhs),
659 self.lower_expr(rhs),
660 )),
661 ast::StmtKind::Qubit(source, lhs, rhs, block) => stmts.push(hir::StmtKind::Qubit(
662 match source {
663 ast::QubitSource::Fresh => hir::QubitSource::Fresh,
664 ast::QubitSource::Dirty => hir::QubitSource::Dirty,
665 },
666 self.lower_pat(lhs),
667 self.lower_qubit_init(rhs),
668 block.as_ref().map(|b| self.lower_block(b)),
669 )),
670 ast::StmtKind::Semi(expr) => stmts.push(hir::StmtKind::Semi(self.lower_expr(expr))),
671 }
672
673 stmts
674 .into_iter()
675 .map(|kind| hir::Stmt {
676 id,
677 span: stmt.span,
678 kind,
679 })
680 .collect()
681 }
682
683 #[allow(clippy::too_many_lines)]
684 fn lower_expr(&mut self, expr: &ast::Expr) -> hir::Expr {
685 if let ast::ExprKind::Paren(inner) = &*expr.kind {
686 return self.lower_expr(inner);
687 }
688
689 let id = self.lower_id(expr.id);
690 let ty = self.tys.terms.get(expr.id).map_or(Ty::Err, Clone::clone);
691
692 let kind = match &*expr.kind {
693 ast::ExprKind::Array(items) => {
694 hir::ExprKind::Array(items.iter().map(|i| self.lower_expr(i)).collect())
695 }
696 ast::ExprKind::ArrayRepeat(value, size) => hir::ExprKind::ArrayRepeat(
697 Box::new(self.lower_expr(value)),
698 Box::new(self.lower_expr(size)),
699 ),
700 ast::ExprKind::Assign(lhs, rhs) => hir::ExprKind::Assign(
701 Box::new(self.lower_expr(lhs)),
702 Box::new(self.lower_expr(rhs)),
703 ),
704 ast::ExprKind::AssignOp(op, lhs, rhs) => hir::ExprKind::AssignOp(
705 lower_binop(*op),
706 Box::new(self.lower_expr(lhs)),
707 Box::new(self.lower_expr(rhs)),
708 ),
709 ast::ExprKind::AssignUpdate(container, index, replace) => {
710 if let Some(field) = resolve::extract_field_name(self.names, index) {
711 let container = self.lower_expr(container);
712 let field = self.lower_field(&container.ty, field);
713 let replace = self.lower_expr(replace);
714 hir::ExprKind::AssignField(Box::new(container), field, Box::new(replace))
715 } else {
716 hir::ExprKind::AssignIndex(
717 Box::new(self.lower_expr(container)),
718 Box::new(self.lower_expr(index)),
719 Box::new(self.lower_expr(replace)),
720 )
721 }
722 }
723 ast::ExprKind::BinOp(op, lhs, rhs) => hir::ExprKind::BinOp(
724 lower_binop(*op),
725 Box::new(self.lower_expr(lhs)),
726 Box::new(self.lower_expr(rhs)),
727 ),
728 ast::ExprKind::Block(block) => hir::ExprKind::Block(self.lower_block(block)),
729 ast::ExprKind::Call(callee, arg) => match &ty {
730 Ty::Arrow(arrow) if is_partial_app(arg) => hir::ExprKind::Block(
731 self.lower_partial_app(callee, arg, arrow.clone(), expr.span),
732 ),
733 _ => hir::ExprKind::Call(
734 Box::new(self.lower_expr(callee)),
735 Box::new(self.lower_expr(arg)),
736 ),
737 },
738 ast::ExprKind::Conjugate(within, apply) => {
739 hir::ExprKind::Conjugate(self.lower_block(within), self.lower_block(apply))
740 }
741 ast::ExprKind::Fail(message) => hir::ExprKind::Fail(Box::new(self.lower_expr(message))),
742 ast::ExprKind::Field(container, FieldAccess::Ok(name)) => {
743 let container = self.lower_expr(container);
744 let field = self.lower_field(&container.ty, &name.name);
745 hir::ExprKind::Field(Box::new(container), field)
746 }
747 ast::ExprKind::For(pat, iter, block) => hir::ExprKind::For(
748 self.lower_pat(pat),
749 Box::new(self.lower_expr(iter)),
750 self.lower_block(block),
751 ),
752 ast::ExprKind::Hole => hir::ExprKind::Hole,
753 ast::ExprKind::If(cond, if_true, if_false) => hir::ExprKind::If(
754 Box::new(self.lower_expr(cond)),
755 Box::new(hir::Expr {
756 id: self.assigner.next_node(),
757 span: if_true.span,
758 ty: self.tys.terms.get(if_true.id).map_or(Ty::Err, Clone::clone),
759 kind: hir::ExprKind::Block(self.lower_block(if_true)),
760 }),
761 if_false.as_ref().map(|e| Box::new(self.lower_expr(e))),
762 ),
763 ast::ExprKind::Index(container, index) => hir::ExprKind::Index(
764 Box::new(self.lower_expr(container)),
765 Box::new(self.lower_expr(index)),
766 ),
767 ast::ExprKind::Lambda(kind, input, body) => {
768 let functors = if let Ty::Arrow(arrow) = &ty {
769 arrow
770 .functors
771 .borrow()
772 .expect_value("lambda type should have concrete functors")
773 } else {
774 FunctorSetValue::Empty
775 };
776 let lambda = Lambda {
777 kind: self.lower_callable_kind(*kind, &[], expr.span),
778 functors,
779 input: self.lower_pat(input),
780 body: self.lower_expr(body),
781 };
782 self.lower_lambda(lambda, expr.span)
783 }
784 ast::ExprKind::Lit(lit) => self.lower_lit(lit),
785 ast::ExprKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
786 ast::ExprKind::Path(PathKind::Ok(path)) => {
787 let args = self
788 .tys
789 .generics
790 .get(expr.id)
791 .map_or(Vec::new(), Clone::clone);
792 self.lower_path(path, args)
793 }
794 ast::ExprKind::Range(start, step, end) => hir::ExprKind::Range(
795 start.as_ref().map(|s| Box::new(self.lower_expr(s))),
796 step.as_ref().map(|s| Box::new(self.lower_expr(s))),
797 end.as_ref().map(|e| Box::new(self.lower_expr(e))),
798 ),
799 ast::ExprKind::Repeat(body, cond, fixup) => hir::ExprKind::Repeat(
800 self.lower_block(body),
801 Box::new(self.lower_expr(cond)),
802 fixup.as_ref().map(|f| self.lower_block(f)),
803 ),
804 ast::ExprKind::Return(expr) => hir::ExprKind::Return(Box::new(self.lower_expr(expr))),
805 ast::ExprKind::Struct(PathKind::Ok(path), copy, fields) => hir::ExprKind::Struct(
806 self.path_to_res(path),
807 copy.as_ref().map(|c| Box::new(self.lower_expr(c))),
808 fields
809 .iter()
810 .map(|f| Box::new(self.lower_field_assign(&ty, f)))
811 .collect(),
812 ),
813 ast::ExprKind::Interpolate(components) => hir::ExprKind::String(
814 components
815 .iter()
816 .map(|c| self.lower_string_component(c))
817 .collect(),
818 ),
819 ast::ExprKind::TernOp(ast::TernOp::Cond, cond, if_true, if_false) => hir::ExprKind::If(
820 Box::new(self.lower_expr(cond)),
821 Box::new(self.lower_expr(if_true)),
822 Some(Box::new(self.lower_expr(if_false))),
823 ),
824 ast::ExprKind::TernOp(ast::TernOp::Update, container, index, replace) => {
825 if let Some(field) = resolve::extract_field_name(self.names, index) {
826 let record = self.lower_expr(container);
827 let field = self.lower_field(&record.ty, field);
828 let replace = self.lower_expr(replace);
829 hir::ExprKind::UpdateField(Box::new(record), field, Box::new(replace))
830 } else {
831 hir::ExprKind::UpdateIndex(
832 Box::new(self.lower_expr(container)),
833 Box::new(self.lower_expr(index)),
834 Box::new(self.lower_expr(replace)),
835 )
836 }
837 }
838 ast::ExprKind::Tuple(items) => {
839 hir::ExprKind::Tuple(items.iter().map(|i| self.lower_expr(i)).collect())
840 }
841 ast::ExprKind::UnOp(op, operand) => {
842 hir::ExprKind::UnOp(lower_unop(*op), Box::new(self.lower_expr(operand)))
843 }
844 ast::ExprKind::While(cond, body) => {
845 hir::ExprKind::While(Box::new(self.lower_expr(cond)), self.lower_block(body))
846 }
847 ast::ExprKind::Err
848 | &ast::ExprKind::Path(ast::PathKind::Err(_))
849 | ast::ExprKind::Struct(ast::PathKind::Err(_), ..)
850 | ast::ExprKind::Field(_, FieldAccess::Err) => hir::ExprKind::Err,
851 };
852
853 hir::Expr {
854 id,
855 span: expr.span,
856 ty,
857 kind,
858 }
859 }
860
861 fn lower_field_assign(&mut self, ty: &Ty, field_assign: &ast::FieldAssign) -> hir::FieldAssign {
862 hir::FieldAssign {
863 id: self.lower_id(field_assign.id),
864 span: field_assign.span,
865 field: self.lower_field(ty, &field_assign.field.name),
866 value: Box::new(self.lower_expr(&field_assign.value)),
867 }
868 }
869
870 fn lower_partial_app(
871 &mut self,
872 callee: &ast::Expr,
873 arg: &ast::Expr,
874 arrow: Rc<Arrow>,
875 span: Span,
876 ) -> hir::Block {
877 let callee = self.lower_expr(callee);
878 let (arg, app) = self.lower_partial_arg(arg);
879 let close = |mut lambda: Lambda| {
880 self.assigner.visit_expr(&mut lambda.body);
881 self.lower_lambda(lambda, span)
882 };
883
884 let mut block = closure::partial_app_block(close, callee, arg, app, arrow, span);
885 self.assigner.visit_block(&mut block);
886 block
887 }
888
889 fn lower_partial_arg(&mut self, arg: &ast::Expr) -> (hir::Expr, PartialApp) {
890 match arg.kind.as_ref() {
891 ast::ExprKind::Hole => {
892 let ty = self.tys.terms.get(arg.id).map_or(Ty::Err, Clone::clone);
893 closure::partial_app_hole(self.assigner, &mut self.lowerer.locals, ty, arg.span)
894 }
895 ast::ExprKind::Paren(inner) => self.lower_partial_arg(inner),
896 ast::ExprKind::Tuple(items) => {
897 let items = items.iter().map(|item| self.lower_partial_arg(item));
898 let (mut arg, mut app) = closure::partial_app_tuple(items, arg.span);
899 self.assigner.visit_expr(&mut arg);
900 self.assigner.visit_pat(&mut app.input);
901 (arg, app)
902 }
903 _ => {
904 let arg = self.lower_expr(arg);
905 closure::partial_app_given(self.assigner, &mut self.lowerer.locals, arg)
906 }
907 }
908 }
909
910 fn lower_lambda(&mut self, lambda: Lambda, span: Span) -> hir::ExprKind {
911 let (args, callable) = closure::lift(self.assigner, &self.lowerer.locals, lambda, span);
912
913 let id = self.assigner.next_item();
914 self.lowerer.items.push(hir::Item {
915 id,
916 span,
917 parent: self.lowerer.parent,
918 doc: "".into(),
919 attrs: Vec::new(),
920 visibility: hir::Visibility::Internal,
921 kind: hir::ItemKind::Callable(callable.into()),
922 });
923
924 hir::ExprKind::Closure(args, id)
925 }
926
927 fn lower_field(&mut self, record_ty: &Ty, name: &str) -> hir::Field {
928 if let Ty::Udt(_, hir::Res::Item(id)) = record_ty {
929 self.tys
930 .udts
931 .get(id)
932 .and_then(|udt| udt.field_path(name))
933 .map_or(hir::Field::Err, hir::Field::Path)
934 } else if let Ok(prim) = name.parse() {
935 hir::Field::Prim(prim)
936 } else {
937 hir::Field::Err
938 }
939 }
940
941 fn lower_string_component(&mut self, component: &ast::StringComponent) -> hir::StringComponent {
942 match component {
943 ast::StringComponent::Expr(expr) => {
944 hir::StringComponent::Expr(self.lower_expr(expr).into())
945 }
946 ast::StringComponent::Lit(str) => hir::StringComponent::Lit(Rc::clone(str)),
947 }
948 }
949
950 fn lower_pat(&mut self, pat: &ast::Pat) -> hir::Pat {
951 if let ast::PatKind::Paren(inner) = &*pat.kind {
952 return self.lower_pat(inner);
953 }
954
955 let id = self.lower_id(pat.id);
956 let ty = self
957 .tys
958 .terms
959 .get(pat.id)
960 .map_or_else(|| convert::ast_pat_ty(self.names, pat).0, Clone::clone);
961
962 let kind = match &*pat.kind {
963 ast::PatKind::Bind(name, _) => {
964 let name = self.lower_ident(name);
965 self.lowerer
966 .locals
967 .insert(name.id, (name.clone(), ty.clone()));
968 hir::PatKind::Bind(name)
969 }
970 ast::PatKind::Discard(_) => hir::PatKind::Discard,
971 ast::PatKind::Elided => {
972 self.lowerer.errors.push(Error::InvalidElidedPat(pat.span));
973 hir::PatKind::Discard
974 }
975 ast::PatKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
976 ast::PatKind::Tuple(items) => {
977 hir::PatKind::Tuple(items.iter().map(|i| self.lower_pat(i)).collect())
978 }
979 ast::PatKind::Err => hir::PatKind::Err,
980 };
981
982 hir::Pat {
983 id,
984 span: pat.span,
985 ty,
986 kind,
987 }
988 }
989
990 fn lower_qubit_init(&mut self, init: &ast::QubitInit) -> hir::QubitInit {
991 if let ast::QubitInitKind::Paren(inner) = &*init.kind {
992 return self.lower_qubit_init(inner);
993 }
994
995 let id = self.lower_id(init.id);
996 let ty = self.tys.terms.get(init.id).map_or(Ty::Err, Clone::clone);
997 let kind = match &*init.kind {
998 ast::QubitInitKind::Array(length) => {
999 hir::QubitInitKind::Array(Box::new(self.lower_expr(length)))
1000 }
1001 ast::QubitInitKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
1002 ast::QubitInitKind::Single => hir::QubitInitKind::Single,
1003 ast::QubitInitKind::Tuple(items) => {
1004 hir::QubitInitKind::Tuple(items.iter().map(|i| self.lower_qubit_init(i)).collect())
1005 }
1006 ast::QubitInitKind::Err => hir::QubitInitKind::Err,
1007 };
1008
1009 hir::QubitInit {
1010 id,
1011 span: init.span,
1012 ty,
1013 kind,
1014 }
1015 }
1016
1017 fn path_to_res(&mut self, path: &ast::Path) -> hir::Res {
1018 match self.names.get(path.id) {
1019 Some(&resolve::Res::Item(item, _)) => hir::Res::Item(item),
1020 Some(&resolve::Res::Local(node)) => hir::Res::Local(self.lower_id(node)),
1021 Some(&resolve::Res::Importable(
1022 resolve::Importable::Callable(item_id, _) | resolve::Importable::Ty(item_id, _),
1023 ..,
1024 )) => hir::Res::Item(item_id),
1025 Some(&resolve::Res::Importable(resolve::Importable::Namespace(_, Some(item_id)))) => {
1026 if item_id.package == self.lowerer.package_id {
1027 hir::Res::Item(item_id)
1028 } else {
1029 // This is a namespace from an external package, and reexporting is
1030 // disallowed since it has no meaningful effect.
1031 self.lowerer
1032 .errors
1033 .push(Error::CrossPackageNamespaceReexport(path.span));
1034 hir::Res::Err
1035 }
1036 }
1037 Some(&resolve::Res::Importable(resolve::Importable::Namespace(_, None))) => {
1038 self.lowerer
1039 .errors
1040 .push(Error::ParentNamespaceExport { span: path.span });
1041 hir::Res::Err
1042 }
1043 Some(resolve::Res::PrimTy(_) | resolve::Res::UnitTy | resolve::Res::Param { .. })
1044 | None => hir::Res::Err,
1045 }
1046 }
1047
1048 fn lower_path(&mut self, path: &ast::Path, generic_args: Vec<GenericArg>) -> hir::ExprKind {
1049 match resolve::path_as_field_accessor(self.names, path) {
1050 Some((first_id, parts)) => {
1051 let res = hir::Res::Local(self.lower_id(first_id));
1052 self.path_parts_to_fields(hir::ExprKind::Var(res, Vec::new()), &parts, path.span.lo)
1053 }
1054 None => hir::ExprKind::Var(self.path_to_res(path), generic_args),
1055 }
1056 }
1057
1058 // Lowers the parts of a field accessor Path into nested Field Accessor nodes.
1059 fn path_parts_to_fields(
1060 &mut self,
1061 init_kind: hir::ExprKind,
1062 parts: &[&Ident],
1063 lo: u32,
1064 ) -> hir::ExprKind {
1065 let (first, rest) = parts
1066 .split_first()
1067 .expect("path should have at least one part");
1068
1069 let mut kind = init_kind;
1070 let mut prev = first;
1071 for part in rest {
1072 let prev_expr = hir::Expr {
1073 id: self.assigner.next_node(),
1074 span: Span {
1075 lo,
1076 hi: prev.span.hi,
1077 },
1078 // The ids of the Ident segments are specially mapped in the tys to give us the type of the expressions being created here.
1079 ty: self.tys.terms.get(prev.id).map_or(Ty::Err, Clone::clone),
1080 kind,
1081 };
1082 let field = self.lower_field(&prev_expr.ty, &part.name);
1083 kind = hir::ExprKind::Field(Box::new(prev_expr), field);
1084 prev = part;
1085 }
1086 kind
1087 }
1088
1089 fn lower_ident(&mut self, ident: &ast::Ident) -> hir::Ident {
1090 hir::Ident {
1091 id: self.lower_id(ident.id),
1092 span: ident.span,
1093 name: ident.name.clone(),
1094 }
1095 }
1096
1097 fn lower_id(&mut self, id: ast::NodeId) -> hir::NodeId {
1098 self.lowerer.nodes.get(id).copied().unwrap_or_else(|| {
1099 let new_id = self.assigner.next_node();
1100 self.lowerer.nodes.insert(id, new_id);
1101 new_id
1102 })
1103 }
1104
1105 fn lower_idents(&mut self, name: &impl Idents) -> hir::Idents {
1106 name.iter().map(|i| self.lower_ident(i)).collect()
1107 }
1108
1109 fn lower_lit(&mut self, lit: &ast::Lit) -> hir::ExprKind {
1110 match lit {
1111 ast::Lit::BigInt(value) => hir::ExprKind::Lit(hir::Lit::BigInt(value.as_ref().clone())),
1112 &ast::Lit::Bool(value) => hir::ExprKind::Lit(hir::Lit::Bool(value)),
1113 &ast::Lit::Double(value) => hir::ExprKind::Lit(hir::Lit::Double(value)),
1114 &ast::Lit::Imaginary(value) => hir::ExprKind::Struct(
1115 hir::Res::Item(ItemId::complex()),
1116 None,
1117 Box::new([
1118 Box::new(hir::FieldAssign {
1119 id: self.assigner.next_node(),
1120 span: Span::default(),
1121 field: hir::Field::Path({
1122 let mut path = hir::FieldPath::default();
1123 path.indices.insert(0, 0);
1124 path
1125 }),
1126 value: Box::new(hir::Expr {
1127 id: self.assigner.next_node(),
1128 span: Span::default(),
1129 ty: Ty::Prim(qsc_hir::ty::Prim::Double),
1130 kind: hir::ExprKind::Lit(hir::Lit::Double(0.0)),
1131 }),
1132 }),
1133 Box::new(hir::FieldAssign {
1134 id: self.assigner.next_node(),
1135 span: Span::default(),
1136 field: hir::Field::Path({
1137 let mut path = hir::FieldPath::default();
1138 path.indices.insert(0, 1);
1139 path
1140 }),
1141 value: Box::new(hir::Expr {
1142 id: self.assigner.next_node(),
1143 span: Span::default(),
1144 ty: Ty::Prim(qsc_hir::ty::Prim::Double),
1145 kind: hir::ExprKind::Lit(hir::Lit::Double(value)),
1146 }),
1147 }),
1148 ]),
1149 ),
1150 &ast::Lit::Int(value) => hir::ExprKind::Lit(hir::Lit::Int(value)),
1151 ast::Lit::Pauli(ast::Pauli::I) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::I)),
1152 ast::Lit::Pauli(ast::Pauli::X) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::X)),
1153 ast::Lit::Pauli(ast::Pauli::Y) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::Y)),
1154 ast::Lit::Pauli(ast::Pauli::Z) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::Z)),
1155 ast::Lit::Result(ast::Result::One) => {
1156 hir::ExprKind::Lit(hir::Lit::Result(hir::Result::One))
1157 }
1158 ast::Lit::Result(ast::Result::Zero) => {
1159 hir::ExprKind::Lit(hir::Lit::Result(hir::Result::Zero))
1160 }
1161 ast::Lit::String(value) => {
1162 hir::ExprKind::String(vec![hir::StringComponent::Lit(Rc::clone(value))])
1163 }
1164 }
1165 }
1166}
1167
1168/// Removes all self-export items, and makes the corresponding item declarations public.
1169///
1170/// Self-exports are exports that refer to items in the same namespace
1171/// with the same name. e.g.:
1172///
1173/// ```qsharp
1174/// namespace A {
1175/// operation B() {} : Unit {}
1176/// export B;
1177/// }
1178/// ```
1179///
1180/// These exports essentially serve to make the original item public, and don't need
1181/// to be lowered as items of their own. In fact, lowering them would result in two
1182/// items with the same name in the same namespace.
1183fn collapse_self_exports(items: &mut IndexMap<LocalItemId, hir::Item>, this_package: PackageId) {
1184 let mut to_export = Vec::new();
1185 for (id, item) in &*items {
1186 if let hir::ItemKind::Export(name, Res::Item(original_item_id)) = &item.kind
1187 && original_item_id.package == this_package
1188 {
1189 let original_item_id = original_item_id.item;
1190 let original_item = items
1191 .get(original_item_id)
1192 .expect("expected to resolve item id");
1193 if let Some(parent_id) = item.parent {
1194 let same_namespace = original_item.parent == item.parent;
1195 let same_name = same_namespace
1196 && match &original_item.kind {
1197 hir::ItemKind::Callable(callable_decl) => {
1198 callable_decl.name.name == name.name
1199 }
1200 hir::ItemKind::Ty(ident, _) => ident.name == name.name,
1201 _ => false,
1202 };
1203 if same_name {
1204 to_export.push((parent_id, id, original_item_id));
1205 }
1206 }
1207 }
1208 }
1209
1210 for (parent_id, export_item_id, original_item_id) in to_export {
1211 // remove the export item
1212 items.remove(export_item_id);
1213 // remove the export item from its parent
1214 if let Some(parent_item) = items.get_mut(parent_id)
1215 && let hir::ItemKind::Namespace(_, local_item_ids) = &mut parent_item.kind
1216 {
1217 local_item_ids.retain(|&id| id != export_item_id);
1218 }
1219 // make the original item public
1220 items
1221 .get_mut(original_item_id)
1222 .expect("expected to resolve item id")
1223 .visibility = Visibility::Public;
1224 }
1225}
1226
1227fn lower_mutability(mutability: ast::Mutability) -> hir::Mutability {
1228 match mutability {
1229 ast::Mutability::Immutable => hir::Mutability::Immutable,
1230 ast::Mutability::Mutable => hir::Mutability::Mutable,
1231 }
1232}
1233
1234fn lower_unop(op: ast::UnOp) -> hir::UnOp {
1235 match op {
1236 ast::UnOp::Functor(f) => hir::UnOp::Functor(lower_functor(f)),
1237 ast::UnOp::Neg => hir::UnOp::Neg,
1238 ast::UnOp::NotB => hir::UnOp::NotB,
1239 ast::UnOp::NotL => hir::UnOp::NotL,
1240 ast::UnOp::Pos => hir::UnOp::Pos,
1241 ast::UnOp::Unwrap => hir::UnOp::Unwrap,
1242 }
1243}
1244
1245fn lower_binop(op: ast::BinOp) -> hir::BinOp {
1246 match op {
1247 ast::BinOp::Add => hir::BinOp::Add,
1248 ast::BinOp::AndB => hir::BinOp::AndB,
1249 ast::BinOp::AndL => hir::BinOp::AndL,
1250 ast::BinOp::Div => hir::BinOp::Div,
1251 ast::BinOp::Eq => hir::BinOp::Eq,
1252 ast::BinOp::Exp => hir::BinOp::Exp,
1253 ast::BinOp::Gt => hir::BinOp::Gt,
1254 ast::BinOp::Gte => hir::BinOp::Gte,
1255 ast::BinOp::Lt => hir::BinOp::Lt,
1256 ast::BinOp::Lte => hir::BinOp::Lte,
1257 ast::BinOp::Mod => hir::BinOp::Mod,
1258 ast::BinOp::Mul => hir::BinOp::Mul,
1259 ast::BinOp::Neq => hir::BinOp::Neq,
1260 ast::BinOp::OrB => hir::BinOp::OrB,
1261 ast::BinOp::OrL => hir::BinOp::OrL,
1262 ast::BinOp::Shl => hir::BinOp::Shl,
1263 ast::BinOp::Shr => hir::BinOp::Shr,
1264 ast::BinOp::Sub => hir::BinOp::Sub,
1265 ast::BinOp::XorB => hir::BinOp::XorB,
1266 }
1267}
1268
1269fn lower_functor(functor: ast::Functor) -> hir::Functor {
1270 match functor {
1271 ast::Functor::Adj => hir::Functor::Adj,
1272 ast::Functor::Ctl => hir::Functor::Ctl,
1273 }
1274}
1275
1276fn is_partial_app(arg: &ast::Expr) -> bool {
1277 match arg.kind.as_ref() {
1278 ast::ExprKind::Hole => true,
1279 ast::ExprKind::Paren(inner) => is_partial_app(inner),
1280 ast::ExprKind::Tuple(items) => items.iter().any(|i| is_partial_app(i)),
1281 _ => false,
1282 }
1283}
1284