microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.29.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc_frontend/src/lower.rs

1298lines · modecode

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