microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc_frontend/src/lower.rs

1297lines · 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 #[allow(clippy::too_many_lines)]
347 fn lower_attr(&mut self, attr: &ast::Attr) -> Option<hir::Attr> {
348 match hir::Attr::from_str(attr.name.name.as_ref()) {
349 Ok(hir::Attr::EntryPoint) => match &*attr.arg.kind {
350 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::EntryPoint),
351 // @EntryPoint(Profile)
352 ast::ExprKind::Paren(inner)
353 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
354 if Profile::from_str(path.name.name.as_ref()).is_ok()) =>
355 {
356 Some(hir::Attr::EntryPoint)
357 }
358 // Any other form is not valid so generates an error.
359 _ => {
360 self.lowerer.errors.push(Error::InvalidAttrArgs(
361 "empty or profile name".to_string(),
362 attr.arg.span,
363 ));
364 None
365 }
366 },
367 Ok(hir::Attr::Unimplemented) => match &*attr.arg.kind {
368 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Unimplemented),
369 _ => {
370 self.lowerer
371 .errors
372 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
373 None
374 }
375 },
376 Ok(hir::Attr::Config) => {
377 match &*attr.arg.kind {
378 // @Config(Capability)
379 ast::ExprKind::Paren(inner)
380 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
381 if TargetCapabilityFlags::from_str(path.name.name.as_ref()).is_ok()) => {}
382
383 // @Config(not Capability)
384 ast::ExprKind::Paren(inner)
385 if matches!(inner.kind.as_ref(), ast::ExprKind::UnOp(ast::UnOp::NotL, inner)
386 if matches!(inner.kind.as_ref(), ast::ExprKind::Path(PathKind::Ok(path))
387 if TargetCapabilityFlags::from_str(path.as_ref().name.name.as_ref()).is_ok())) =>
388 {}
389
390 // Any other form is not valid so generates an error.
391 _ => {
392 self.lowerer.errors.push(Error::InvalidAttrArgs(
393 "runtime capability".to_string(),
394 attr.arg.span,
395 ));
396 }
397 }
398 None
399 }
400 Ok(hir::Attr::SimulatableIntrinsic) => match &*attr.arg.kind {
401 ast::ExprKind::Tuple(args) if args.is_empty() => {
402 Some(hir::Attr::SimulatableIntrinsic)
403 }
404 _ => {
405 self.lowerer
406 .errors
407 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
408 None
409 }
410 },
411 Ok(hir::Attr::Measurement) => match &*attr.arg.kind {
412 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Measurement),
413 _ => {
414 self.lowerer
415 .errors
416 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
417 None
418 }
419 },
420 Ok(hir::Attr::Reset) => match &*attr.arg.kind {
421 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::Reset),
422 _ => {
423 self.lowerer
424 .errors
425 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
426 None
427 }
428 },
429 Ok(hir::Attr::NoiseIntrinsic) => match &*attr.arg.kind {
430 ast::ExprKind::Tuple(args) if args.is_empty() => Some(hir::Attr::NoiseIntrinsic),
431 _ => {
432 self.lowerer
433 .errors
434 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
435 None
436 }
437 },
438 Ok(hir::Attr::Test) => {
439 // verify that no args are passed to the attribute
440 match &*attr.arg.kind {
441 ast::ExprKind::Tuple(args) if args.is_empty() => {}
442 _ => {
443 self.lowerer
444 .errors
445 .push(Error::InvalidAttrArgs("()".to_string(), attr.arg.span));
446 }
447 }
448 // lower the attribute even if it has invalid args
449 Some(hir::Attr::Test)
450 }
451 Err(()) => {
452 self.lowerer.errors.push(Error::UnknownAttr(
453 attr.name.name.to_string(),
454 attr.name.span,
455 ));
456 None
457 }
458 }
459 }
460
461 /// Generates generic parameters for the functors, if there were generics on the original callable.
462 /// Basically just creates new generic params for the purpose of being used in functor callable
463 /// decls.
464 pub(crate) fn synthesize_callable_generics(
465 &mut self,
466 generics: &[ast::TypeParameter],
467 input: &mut hir::Pat,
468 ) -> (Vec<qsc_hir::ty::TypeParameter>, Vec<TyConversionError>) {
469 let (mut params, errs) = convert::type_parameters_for_ast_callable(self.names, generics);
470 let mut functor_params =
471 Self::synthesize_functor_params_in_pat(&mut params.len().into(), input);
472 params.append(&mut functor_params);
473 (params, errs)
474 }
475
476 fn synthesize_functor_params_in_pat(
477 next_param: &mut ParamId,
478 pat: &mut hir::Pat,
479 ) -> Vec<TypeParameter> {
480 match &mut pat.kind {
481 hir::PatKind::Discard | hir::PatKind::Err | hir::PatKind::Bind(_) => {
482 synthesize_functor_params(next_param, &mut pat.ty)
483 }
484 hir::PatKind::Tuple(items) => {
485 let mut params = Vec::new();
486 for item in &mut *items {
487 params.append(&mut Self::synthesize_functor_params_in_pat(
488 next_param, item,
489 ));
490 }
491 if !params.is_empty() {
492 pat.ty = Ty::Tuple(items.iter().map(|i| i.ty.clone()).collect());
493 }
494 params
495 }
496 }
497 }
498
499 pub(super) fn lower_callable_decl(
500 &mut self,
501 decl: &ast::CallableDecl,
502 attrs: &[qsc_hir::hir::Attr],
503 ) -> (hir::CallableDecl, Vec<TyConversionError>) {
504 let id = self.lower_id(decl.id);
505 let kind = self.lower_callable_kind(decl.kind, attrs, decl.name.span);
506 let name = self.lower_ident(&decl.name);
507 let mut input = self.lower_pat(&decl.input);
508 let output = convert::ty_from_ast(self.names, &decl.output, &mut Default::default()).0;
509 let (generics, errs) = self.synthesize_callable_generics(&decl.generics, &mut input);
510 let functors = convert::ast_callable_functors(decl);
511
512 let (body, adj, ctl, ctl_adj) = match decl.body.as_ref() {
513 ast::CallableBody::Block(block) => {
514 let body = hir::SpecDecl {
515 id: self.assigner.next_node(),
516 span: decl.span,
517 body: hir::SpecBody::Impl(None, self.lower_block(block)),
518 };
519 (body, None, None, None)
520 }
521 ast::CallableBody::Specs(specs) => {
522 let body = self.find_spec(specs, ast::Spec::Body).unwrap_or_else(|| {
523 self.lowerer.errors.push(Error::MissingBody(decl.span));
524 hir::SpecDecl {
525 id: self.assigner.next_node(),
526 span: decl.span,
527 body: hir::SpecBody::Gen(hir::SpecGen::Auto),
528 }
529 });
530 let adj = self.find_spec(specs, ast::Spec::Adj);
531 let ctl = self.find_spec(specs, ast::Spec::Ctl);
532 let ctl_adj = self.find_spec(specs, ast::Spec::CtlAdj);
533 (body, adj, ctl, ctl_adj)
534 }
535 };
536
537 (
538 hir::CallableDecl {
539 id,
540 span: decl.span,
541 kind,
542 name,
543 generics,
544 input,
545 output,
546 functors,
547 body,
548 adj,
549 ctl,
550 ctl_adj,
551 attrs: attrs.to_vec(),
552 },
553 errs,
554 )
555 }
556
557 fn check_invalid_attrs_on_function(&mut self, attrs: &[hir::Attr], span: Span) {
558 const INVALID_ATTRS: [hir::Attr; 3] = [
559 hir::Attr::Measurement,
560 hir::Attr::Reset,
561 hir::Attr::NoiseIntrinsic,
562 ];
563
564 for invalid_attr in &INVALID_ATTRS {
565 if attrs.contains(invalid_attr) {
566 self.lowerer.errors.push(Error::InvalidAttrOnFunction(
567 format!("{invalid_attr:?}"),
568 span,
569 ));
570 }
571 }
572 }
573
574 fn lower_callable_kind(
575 &mut self,
576 kind: ast::CallableKind,
577 attrs: &[hir::Attr],
578 span: Span,
579 ) -> hir::CallableKind {
580 match kind {
581 ast::CallableKind::Function => {
582 self.check_invalid_attrs_on_function(attrs, span);
583 hir::CallableKind::Function
584 }
585 ast::CallableKind::Operation => hir::CallableKind::Operation,
586 }
587 }
588
589 fn find_spec(
590 &mut self,
591 specs: &[Box<ast::SpecDecl>],
592 spec: ast::Spec,
593 ) -> Option<hir::SpecDecl> {
594 match specs
595 .iter()
596 .filter(|s| s.spec == spec)
597 .collect::<Vec<_>>()
598 .as_slice()
599 {
600 [] => None,
601 [single] => Some(self.lower_spec_decl(single)),
602 dupes => {
603 for dup in dupes {
604 self.lowerer.errors.push(Error::DuplicateSpec(dup.span));
605 }
606 Some(self.lower_spec_decl(dupes[0]))
607 }
608 }
609 }
610
611 fn lower_spec_decl(&mut self, decl: &ast::SpecDecl) -> hir::SpecDecl {
612 hir::SpecDecl {
613 id: self.lower_id(decl.id),
614 span: decl.span,
615 body: match &decl.body {
616 ast::SpecBody::Gen(spec_gen) => hir::SpecBody::Gen(match spec_gen {
617 ast::SpecGen::Auto => hir::SpecGen::Auto,
618 ast::SpecGen::Distribute => hir::SpecGen::Distribute,
619 ast::SpecGen::Intrinsic => hir::SpecGen::Intrinsic,
620 ast::SpecGen::Invert => hir::SpecGen::Invert,
621 ast::SpecGen::Slf => hir::SpecGen::Slf,
622 }),
623 ast::SpecBody::Impl(input, block) => {
624 hir::SpecBody::Impl(self.lower_spec_decl_pat(input), self.lower_block(block))
625 }
626 },
627 }
628 }
629
630 fn lower_spec_decl_pat(&mut self, pat: &ast::Pat) -> Option<hir::Pat> {
631 if let ast::PatKind::Paren(inner) = &*pat.kind {
632 return self.lower_spec_decl_pat(inner);
633 }
634
635 match &*pat.kind {
636 ast::PatKind::Elided => return None,
637 ast::PatKind::Tuple(items)
638 if items.len() == 2 && *items[1].kind == ast::PatKind::Elided =>
639 {
640 return Some(self.lower_pat(&items[0]));
641 }
642 _ => self.lowerer.errors.push(Error::InvalidSpecPat(pat.span)),
643 }
644
645 None
646 }
647
648 fn lower_block(&mut self, block: &ast::Block) -> hir::Block {
649 hir::Block {
650 id: self.lower_id(block.id),
651 span: block.span,
652 ty: self.tys.terms.get(block.id).map_or(Ty::Err, Clone::clone),
653 stmts: block
654 .stmts
655 .iter()
656 .flat_map(|s| self.lower_stmt(s))
657 .collect(),
658 }
659 }
660
661 pub(super) fn lower_stmt(&mut self, stmt: &ast::Stmt) -> Vec<hir::Stmt> {
662 let id = self.lower_id(stmt.id);
663 let mut stmts = Vec::new();
664 match &*stmt.kind {
665 ast::StmtKind::Empty | ast::StmtKind::Err => {}
666 ast::StmtKind::Expr(expr) => stmts.push(hir::StmtKind::Expr(self.lower_expr(expr))),
667 ast::StmtKind::Item(item) => {
668 stmts.extend(self.lower_item(item).into_iter().map(hir::StmtKind::Item));
669 }
670 ast::StmtKind::Local(mutability, lhs, rhs) => stmts.push(hir::StmtKind::Local(
671 lower_mutability(*mutability),
672 self.lower_pat(lhs),
673 self.lower_expr(rhs),
674 )),
675 ast::StmtKind::Qubit(source, lhs, rhs, block) => stmts.push(hir::StmtKind::Qubit(
676 match source {
677 ast::QubitSource::Fresh => hir::QubitSource::Fresh,
678 ast::QubitSource::Dirty => hir::QubitSource::Dirty,
679 },
680 self.lower_pat(lhs),
681 self.lower_qubit_init(rhs),
682 block.as_ref().map(|b| self.lower_block(b)),
683 )),
684 ast::StmtKind::Semi(expr) => stmts.push(hir::StmtKind::Semi(self.lower_expr(expr))),
685 }
686
687 stmts
688 .into_iter()
689 .map(|kind| hir::Stmt {
690 id,
691 span: stmt.span,
692 kind,
693 })
694 .collect()
695 }
696
697 #[allow(clippy::too_many_lines)]
698 fn lower_expr(&mut self, expr: &ast::Expr) -> hir::Expr {
699 if let ast::ExprKind::Paren(inner) = &*expr.kind {
700 return self.lower_expr(inner);
701 }
702
703 let id = self.lower_id(expr.id);
704 let ty = self.tys.terms.get(expr.id).map_or(Ty::Err, Clone::clone);
705
706 let kind = match &*expr.kind {
707 ast::ExprKind::Array(items) => {
708 hir::ExprKind::Array(items.iter().map(|i| self.lower_expr(i)).collect())
709 }
710 ast::ExprKind::ArrayRepeat(value, size) => hir::ExprKind::ArrayRepeat(
711 Box::new(self.lower_expr(value)),
712 Box::new(self.lower_expr(size)),
713 ),
714 ast::ExprKind::Assign(lhs, rhs) => hir::ExprKind::Assign(
715 Box::new(self.lower_expr(lhs)),
716 Box::new(self.lower_expr(rhs)),
717 ),
718 ast::ExprKind::AssignOp(op, lhs, rhs) => hir::ExprKind::AssignOp(
719 lower_binop(*op),
720 Box::new(self.lower_expr(lhs)),
721 Box::new(self.lower_expr(rhs)),
722 ),
723 ast::ExprKind::AssignUpdate(container, index, replace) => {
724 if let Some(field) = resolve::extract_field_name(self.names, index) {
725 let container = self.lower_expr(container);
726 let field = self.lower_field(&container.ty, field);
727 let replace = self.lower_expr(replace);
728 hir::ExprKind::AssignField(Box::new(container), field, Box::new(replace))
729 } else {
730 hir::ExprKind::AssignIndex(
731 Box::new(self.lower_expr(container)),
732 Box::new(self.lower_expr(index)),
733 Box::new(self.lower_expr(replace)),
734 )
735 }
736 }
737 ast::ExprKind::BinOp(op, lhs, rhs) => hir::ExprKind::BinOp(
738 lower_binop(*op),
739 Box::new(self.lower_expr(lhs)),
740 Box::new(self.lower_expr(rhs)),
741 ),
742 ast::ExprKind::Block(block) => hir::ExprKind::Block(self.lower_block(block)),
743 ast::ExprKind::Call(callee, arg) => match &ty {
744 Ty::Arrow(arrow) if is_partial_app(arg) => hir::ExprKind::Block(
745 self.lower_partial_app(callee, arg, arrow.clone(), expr.span),
746 ),
747 _ => hir::ExprKind::Call(
748 Box::new(self.lower_expr(callee)),
749 Box::new(self.lower_expr(arg)),
750 ),
751 },
752 ast::ExprKind::Conjugate(within, apply) => {
753 hir::ExprKind::Conjugate(self.lower_block(within), self.lower_block(apply))
754 }
755 ast::ExprKind::Fail(message) => hir::ExprKind::Fail(Box::new(self.lower_expr(message))),
756 ast::ExprKind::Field(container, FieldAccess::Ok(name)) => {
757 let container = self.lower_expr(container);
758 let field = self.lower_field(&container.ty, &name.name);
759 hir::ExprKind::Field(Box::new(container), field)
760 }
761 ast::ExprKind::For(pat, iter, block) => hir::ExprKind::For(
762 self.lower_pat(pat),
763 Box::new(self.lower_expr(iter)),
764 self.lower_block(block),
765 ),
766 ast::ExprKind::Hole => hir::ExprKind::Hole,
767 ast::ExprKind::If(cond, if_true, if_false) => hir::ExprKind::If(
768 Box::new(self.lower_expr(cond)),
769 Box::new(hir::Expr {
770 id: self.assigner.next_node(),
771 span: if_true.span,
772 ty: self.tys.terms.get(if_true.id).map_or(Ty::Err, Clone::clone),
773 kind: hir::ExprKind::Block(self.lower_block(if_true)),
774 }),
775 if_false.as_ref().map(|e| Box::new(self.lower_expr(e))),
776 ),
777 ast::ExprKind::Index(container, index) => hir::ExprKind::Index(
778 Box::new(self.lower_expr(container)),
779 Box::new(self.lower_expr(index)),
780 ),
781 ast::ExprKind::Lambda(kind, input, body) => {
782 let functors = if let Ty::Arrow(arrow) = &ty {
783 arrow
784 .functors
785 .borrow()
786 .expect_value("lambda type should have concrete functors")
787 } else {
788 FunctorSetValue::Empty
789 };
790 let lambda = Lambda {
791 kind: self.lower_callable_kind(*kind, &[], expr.span),
792 functors,
793 input: self.lower_pat(input),
794 body: self.lower_expr(body),
795 };
796 self.lower_lambda(lambda, expr.span)
797 }
798 ast::ExprKind::Lit(lit) => self.lower_lit(lit),
799 ast::ExprKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
800 ast::ExprKind::Path(PathKind::Ok(path)) => {
801 let args = self
802 .tys
803 .generics
804 .get(expr.id)
805 .map_or(Vec::new(), Clone::clone);
806 self.lower_path(path, args)
807 }
808 ast::ExprKind::Range(start, step, end) => hir::ExprKind::Range(
809 start.as_ref().map(|s| Box::new(self.lower_expr(s))),
810 step.as_ref().map(|s| Box::new(self.lower_expr(s))),
811 end.as_ref().map(|e| Box::new(self.lower_expr(e))),
812 ),
813 ast::ExprKind::Repeat(body, cond, fixup) => hir::ExprKind::Repeat(
814 self.lower_block(body),
815 Box::new(self.lower_expr(cond)),
816 fixup.as_ref().map(|f| self.lower_block(f)),
817 ),
818 ast::ExprKind::Return(expr) => hir::ExprKind::Return(Box::new(self.lower_expr(expr))),
819 ast::ExprKind::Struct(PathKind::Ok(path), copy, fields) => hir::ExprKind::Struct(
820 self.path_to_res(path),
821 copy.as_ref().map(|c| Box::new(self.lower_expr(c))),
822 fields
823 .iter()
824 .map(|f| Box::new(self.lower_field_assign(&ty, f)))
825 .collect(),
826 ),
827 ast::ExprKind::Interpolate(components) => hir::ExprKind::String(
828 components
829 .iter()
830 .map(|c| self.lower_string_component(c))
831 .collect(),
832 ),
833 ast::ExprKind::TernOp(ast::TernOp::Cond, cond, if_true, if_false) => hir::ExprKind::If(
834 Box::new(self.lower_expr(cond)),
835 Box::new(self.lower_expr(if_true)),
836 Some(Box::new(self.lower_expr(if_false))),
837 ),
838 ast::ExprKind::TernOp(ast::TernOp::Update, container, index, replace) => {
839 if let Some(field) = resolve::extract_field_name(self.names, index) {
840 let record = self.lower_expr(container);
841 let field = self.lower_field(&record.ty, field);
842 let replace = self.lower_expr(replace);
843 hir::ExprKind::UpdateField(Box::new(record), field, Box::new(replace))
844 } else {
845 hir::ExprKind::UpdateIndex(
846 Box::new(self.lower_expr(container)),
847 Box::new(self.lower_expr(index)),
848 Box::new(self.lower_expr(replace)),
849 )
850 }
851 }
852 ast::ExprKind::Tuple(items) => {
853 hir::ExprKind::Tuple(items.iter().map(|i| self.lower_expr(i)).collect())
854 }
855 ast::ExprKind::UnOp(op, operand) => {
856 hir::ExprKind::UnOp(lower_unop(*op), Box::new(self.lower_expr(operand)))
857 }
858 ast::ExprKind::While(cond, body) => {
859 hir::ExprKind::While(Box::new(self.lower_expr(cond)), self.lower_block(body))
860 }
861 ast::ExprKind::Err
862 | &ast::ExprKind::Path(ast::PathKind::Err(_))
863 | ast::ExprKind::Struct(ast::PathKind::Err(_), ..)
864 | ast::ExprKind::Field(_, FieldAccess::Err) => hir::ExprKind::Err,
865 };
866
867 hir::Expr {
868 id,
869 span: expr.span,
870 ty,
871 kind,
872 }
873 }
874
875 fn lower_field_assign(&mut self, ty: &Ty, field_assign: &ast::FieldAssign) -> hir::FieldAssign {
876 hir::FieldAssign {
877 id: self.lower_id(field_assign.id),
878 span: field_assign.span,
879 field: self.lower_field(ty, &field_assign.field.name),
880 value: Box::new(self.lower_expr(&field_assign.value)),
881 }
882 }
883
884 fn lower_partial_app(
885 &mut self,
886 callee: &ast::Expr,
887 arg: &ast::Expr,
888 arrow: Rc<Arrow>,
889 span: Span,
890 ) -> hir::Block {
891 let callee = self.lower_expr(callee);
892 let (arg, app) = self.lower_partial_arg(arg);
893 let close = |mut lambda: Lambda| {
894 self.assigner.visit_expr(&mut lambda.body);
895 self.lower_lambda(lambda, span)
896 };
897
898 let mut block = closure::partial_app_block(close, callee, arg, app, arrow, span);
899 self.assigner.visit_block(&mut block);
900 block
901 }
902
903 fn lower_partial_arg(&mut self, arg: &ast::Expr) -> (hir::Expr, PartialApp) {
904 match arg.kind.as_ref() {
905 ast::ExprKind::Hole => {
906 let ty = self.tys.terms.get(arg.id).map_or(Ty::Err, Clone::clone);
907 closure::partial_app_hole(self.assigner, &mut self.lowerer.locals, ty, arg.span)
908 }
909 ast::ExprKind::Paren(inner) => self.lower_partial_arg(inner),
910 ast::ExprKind::Tuple(items) => {
911 let items = items.iter().map(|item| self.lower_partial_arg(item));
912 let (mut arg, mut app) = closure::partial_app_tuple(items, arg.span);
913 self.assigner.visit_expr(&mut arg);
914 self.assigner.visit_pat(&mut app.input);
915 (arg, app)
916 }
917 _ => {
918 let arg = self.lower_expr(arg);
919 closure::partial_app_given(self.assigner, &mut self.lowerer.locals, arg)
920 }
921 }
922 }
923
924 fn lower_lambda(&mut self, lambda: Lambda, span: Span) -> hir::ExprKind {
925 let (args, callable) = closure::lift(self.assigner, &self.lowerer.locals, lambda, span);
926
927 let id = self.assigner.next_item();
928 self.lowerer.items.push(hir::Item {
929 id,
930 span,
931 parent: self.lowerer.parent,
932 doc: "".into(),
933 attrs: Vec::new(),
934 visibility: hir::Visibility::Internal,
935 kind: hir::ItemKind::Callable(callable.into()),
936 });
937
938 hir::ExprKind::Closure(args, id)
939 }
940
941 fn lower_field(&mut self, record_ty: &Ty, name: &str) -> hir::Field {
942 if let Ty::Udt(_, hir::Res::Item(id)) = record_ty {
943 self.tys
944 .udts
945 .get(id)
946 .and_then(|udt| udt.field_path(name))
947 .map_or(hir::Field::Err, hir::Field::Path)
948 } else if let Ok(prim) = name.parse() {
949 hir::Field::Prim(prim)
950 } else {
951 hir::Field::Err
952 }
953 }
954
955 fn lower_string_component(&mut self, component: &ast::StringComponent) -> hir::StringComponent {
956 match component {
957 ast::StringComponent::Expr(expr) => {
958 hir::StringComponent::Expr(self.lower_expr(expr).into())
959 }
960 ast::StringComponent::Lit(str) => hir::StringComponent::Lit(Rc::clone(str)),
961 }
962 }
963
964 fn lower_pat(&mut self, pat: &ast::Pat) -> hir::Pat {
965 if let ast::PatKind::Paren(inner) = &*pat.kind {
966 return self.lower_pat(inner);
967 }
968
969 let id = self.lower_id(pat.id);
970 let ty = self
971 .tys
972 .terms
973 .get(pat.id)
974 .map_or_else(|| convert::ast_pat_ty(self.names, pat).0, Clone::clone);
975
976 let kind = match &*pat.kind {
977 ast::PatKind::Bind(name, _) => {
978 let name = self.lower_ident(name);
979 self.lowerer
980 .locals
981 .insert(name.id, (name.clone(), ty.clone()));
982 hir::PatKind::Bind(name)
983 }
984 ast::PatKind::Discard(_) => hir::PatKind::Discard,
985 ast::PatKind::Elided => {
986 self.lowerer.errors.push(Error::InvalidElidedPat(pat.span));
987 hir::PatKind::Discard
988 }
989 ast::PatKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
990 ast::PatKind::Tuple(items) => {
991 hir::PatKind::Tuple(items.iter().map(|i| self.lower_pat(i)).collect())
992 }
993 ast::PatKind::Err => hir::PatKind::Err,
994 };
995
996 hir::Pat {
997 id,
998 span: pat.span,
999 ty,
1000 kind,
1001 }
1002 }
1003
1004 fn lower_qubit_init(&mut self, init: &ast::QubitInit) -> hir::QubitInit {
1005 if let ast::QubitInitKind::Paren(inner) = &*init.kind {
1006 return self.lower_qubit_init(inner);
1007 }
1008
1009 let id = self.lower_id(init.id);
1010 let ty = self.tys.terms.get(init.id).map_or(Ty::Err, Clone::clone);
1011 let kind = match &*init.kind {
1012 ast::QubitInitKind::Array(length) => {
1013 hir::QubitInitKind::Array(Box::new(self.lower_expr(length)))
1014 }
1015 ast::QubitInitKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
1016 ast::QubitInitKind::Single => hir::QubitInitKind::Single,
1017 ast::QubitInitKind::Tuple(items) => {
1018 hir::QubitInitKind::Tuple(items.iter().map(|i| self.lower_qubit_init(i)).collect())
1019 }
1020 ast::QubitInitKind::Err => hir::QubitInitKind::Err,
1021 };
1022
1023 hir::QubitInit {
1024 id,
1025 span: init.span,
1026 ty,
1027 kind,
1028 }
1029 }
1030
1031 fn path_to_res(&mut self, path: &ast::Path) -> hir::Res {
1032 match self.names.get(path.id) {
1033 Some(&resolve::Res::Item(item, _)) => hir::Res::Item(item),
1034 Some(&resolve::Res::Local(node)) => hir::Res::Local(self.lower_id(node)),
1035 Some(&resolve::Res::Importable(
1036 resolve::Importable::Callable(item_id, _) | resolve::Importable::Ty(item_id, _),
1037 ..,
1038 )) => hir::Res::Item(item_id),
1039 Some(&resolve::Res::Importable(resolve::Importable::Namespace(_, Some(item_id)))) => {
1040 if item_id.package == self.lowerer.package_id {
1041 hir::Res::Item(item_id)
1042 } else {
1043 // This is a namespace from an external package, and reexporting is
1044 // disallowed since it has no meaningful effect.
1045 self.lowerer
1046 .errors
1047 .push(Error::CrossPackageNamespaceReexport(path.span));
1048 hir::Res::Err
1049 }
1050 }
1051 Some(&resolve::Res::Importable(resolve::Importable::Namespace(_, None))) => {
1052 self.lowerer
1053 .errors
1054 .push(Error::ParentNamespaceExport { span: path.span });
1055 hir::Res::Err
1056 }
1057 Some(resolve::Res::PrimTy(_) | resolve::Res::UnitTy | resolve::Res::Param { .. })
1058 | None => hir::Res::Err,
1059 }
1060 }
1061
1062 fn lower_path(&mut self, path: &ast::Path, generic_args: Vec<GenericArg>) -> hir::ExprKind {
1063 match resolve::path_as_field_accessor(self.names, path) {
1064 Some((first_id, parts)) => {
1065 let res = hir::Res::Local(self.lower_id(first_id));
1066 self.path_parts_to_fields(hir::ExprKind::Var(res, Vec::new()), &parts, path.span.lo)
1067 }
1068 None => hir::ExprKind::Var(self.path_to_res(path), generic_args),
1069 }
1070 }
1071
1072 // Lowers the parts of a field accessor Path into nested Field Accessor nodes.
1073 fn path_parts_to_fields(
1074 &mut self,
1075 init_kind: hir::ExprKind,
1076 parts: &[&Ident],
1077 lo: u32,
1078 ) -> hir::ExprKind {
1079 let (first, rest) = parts
1080 .split_first()
1081 .expect("path should have at least one part");
1082
1083 let mut kind = init_kind;
1084 let mut prev = first;
1085 for part in rest {
1086 let prev_expr = hir::Expr {
1087 id: self.assigner.next_node(),
1088 span: Span {
1089 lo,
1090 hi: prev.span.hi,
1091 },
1092 // The ids of the Ident segments are specially mapped in the tys to give us the type of the expressions being created here.
1093 ty: self.tys.terms.get(prev.id).map_or(Ty::Err, Clone::clone),
1094 kind,
1095 };
1096 let field = self.lower_field(&prev_expr.ty, &part.name);
1097 kind = hir::ExprKind::Field(Box::new(prev_expr), field);
1098 prev = part;
1099 }
1100 kind
1101 }
1102
1103 fn lower_ident(&mut self, ident: &ast::Ident) -> hir::Ident {
1104 hir::Ident {
1105 id: self.lower_id(ident.id),
1106 span: ident.span,
1107 name: ident.name.clone(),
1108 }
1109 }
1110
1111 fn lower_id(&mut self, id: ast::NodeId) -> hir::NodeId {
1112 self.lowerer.nodes.get(id).copied().unwrap_or_else(|| {
1113 let new_id = self.assigner.next_node();
1114 self.lowerer.nodes.insert(id, new_id);
1115 new_id
1116 })
1117 }
1118
1119 fn lower_idents(&mut self, name: &impl Idents) -> hir::Idents {
1120 name.iter().map(|i| self.lower_ident(i)).collect()
1121 }
1122
1123 fn lower_lit(&mut self, lit: &ast::Lit) -> hir::ExprKind {
1124 match lit {
1125 ast::Lit::BigInt(value) => hir::ExprKind::Lit(hir::Lit::BigInt(value.as_ref().clone())),
1126 &ast::Lit::Bool(value) => hir::ExprKind::Lit(hir::Lit::Bool(value)),
1127 &ast::Lit::Double(value) => hir::ExprKind::Lit(hir::Lit::Double(value)),
1128 &ast::Lit::Imaginary(value) => hir::ExprKind::Struct(
1129 hir::Res::Item(ItemId::complex()),
1130 None,
1131 Box::new([
1132 Box::new(hir::FieldAssign {
1133 id: self.assigner.next_node(),
1134 span: Span::default(),
1135 field: hir::Field::Path({
1136 let mut path = hir::FieldPath::default();
1137 path.indices.insert(0, 0);
1138 path
1139 }),
1140 value: Box::new(hir::Expr {
1141 id: self.assigner.next_node(),
1142 span: Span::default(),
1143 ty: Ty::Prim(qsc_hir::ty::Prim::Double),
1144 kind: hir::ExprKind::Lit(hir::Lit::Double(0.0)),
1145 }),
1146 }),
1147 Box::new(hir::FieldAssign {
1148 id: self.assigner.next_node(),
1149 span: Span::default(),
1150 field: hir::Field::Path({
1151 let mut path = hir::FieldPath::default();
1152 path.indices.insert(0, 1);
1153 path
1154 }),
1155 value: Box::new(hir::Expr {
1156 id: self.assigner.next_node(),
1157 span: Span::default(),
1158 ty: Ty::Prim(qsc_hir::ty::Prim::Double),
1159 kind: hir::ExprKind::Lit(hir::Lit::Double(value)),
1160 }),
1161 }),
1162 ]),
1163 ),
1164 &ast::Lit::Int(value) => hir::ExprKind::Lit(hir::Lit::Int(value)),
1165 ast::Lit::Pauli(ast::Pauli::I) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::I)),
1166 ast::Lit::Pauli(ast::Pauli::X) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::X)),
1167 ast::Lit::Pauli(ast::Pauli::Y) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::Y)),
1168 ast::Lit::Pauli(ast::Pauli::Z) => hir::ExprKind::Lit(hir::Lit::Pauli(hir::Pauli::Z)),
1169 ast::Lit::Result(ast::Result::One) => {
1170 hir::ExprKind::Lit(hir::Lit::Result(hir::Result::One))
1171 }
1172 ast::Lit::Result(ast::Result::Zero) => {
1173 hir::ExprKind::Lit(hir::Lit::Result(hir::Result::Zero))
1174 }
1175 ast::Lit::String(value) => {
1176 hir::ExprKind::String(vec![hir::StringComponent::Lit(Rc::clone(value))])
1177 }
1178 }
1179 }
1180}
1181
1182/// Removes all self-export items, and makes the corresponding item declarations public.
1183///
1184/// Self-exports are exports that refer to items in the same namespace
1185/// with the same name. e.g.:
1186///
1187/// ```qsharp
1188/// namespace A {
1189/// operation B() {} : Unit {}
1190/// export B;
1191/// }
1192/// ```
1193///
1194/// These exports essentially serve to make the original item public, and don't need
1195/// to be lowered as items of their own. In fact, lowering them would result in two
1196/// items with the same name in the same namespace.
1197fn collapse_self_exports(items: &mut IndexMap<LocalItemId, hir::Item>, this_package: PackageId) {
1198 let mut to_export = Vec::new();
1199 for (id, item) in &*items {
1200 if let hir::ItemKind::Export(name, Res::Item(original_item_id)) = &item.kind
1201 && original_item_id.package == this_package
1202 {
1203 let original_item_id = original_item_id.item;
1204 let original_item = items
1205 .get(original_item_id)
1206 .expect("expected to resolve item id");
1207 if let Some(parent_id) = item.parent {
1208 let same_namespace = original_item.parent == item.parent;
1209 let same_name = same_namespace
1210 && match &original_item.kind {
1211 hir::ItemKind::Callable(callable_decl) => {
1212 callable_decl.name.name == name.name
1213 }
1214 hir::ItemKind::Ty(ident, _) => ident.name == name.name,
1215 _ => false,
1216 };
1217 if same_name {
1218 to_export.push((parent_id, id, original_item_id));
1219 }
1220 }
1221 }
1222 }
1223
1224 for (parent_id, export_item_id, original_item_id) in to_export {
1225 // remove the export item
1226 items.remove(export_item_id);
1227 // remove the export item from its parent
1228 if let Some(parent_item) = items.get_mut(parent_id)
1229 && let hir::ItemKind::Namespace(_, local_item_ids) = &mut parent_item.kind
1230 {
1231 local_item_ids.retain(|&id| id != export_item_id);
1232 }
1233 // make the original item public
1234 items
1235 .get_mut(original_item_id)
1236 .expect("expected to resolve item id")
1237 .visibility = Visibility::Public;
1238 }
1239}
1240
1241fn lower_mutability(mutability: ast::Mutability) -> hir::Mutability {
1242 match mutability {
1243 ast::Mutability::Immutable => hir::Mutability::Immutable,
1244 ast::Mutability::Mutable => hir::Mutability::Mutable,
1245 }
1246}
1247
1248fn lower_unop(op: ast::UnOp) -> hir::UnOp {
1249 match op {
1250 ast::UnOp::Functor(f) => hir::UnOp::Functor(lower_functor(f)),
1251 ast::UnOp::Neg => hir::UnOp::Neg,
1252 ast::UnOp::NotB => hir::UnOp::NotB,
1253 ast::UnOp::NotL => hir::UnOp::NotL,
1254 ast::UnOp::Pos => hir::UnOp::Pos,
1255 ast::UnOp::Unwrap => hir::UnOp::Unwrap,
1256 }
1257}
1258
1259fn lower_binop(op: ast::BinOp) -> hir::BinOp {
1260 match op {
1261 ast::BinOp::Add => hir::BinOp::Add,
1262 ast::BinOp::AndB => hir::BinOp::AndB,
1263 ast::BinOp::AndL => hir::BinOp::AndL,
1264 ast::BinOp::Div => hir::BinOp::Div,
1265 ast::BinOp::Eq => hir::BinOp::Eq,
1266 ast::BinOp::Exp => hir::BinOp::Exp,
1267 ast::BinOp::Gt => hir::BinOp::Gt,
1268 ast::BinOp::Gte => hir::BinOp::Gte,
1269 ast::BinOp::Lt => hir::BinOp::Lt,
1270 ast::BinOp::Lte => hir::BinOp::Lte,
1271 ast::BinOp::Mod => hir::BinOp::Mod,
1272 ast::BinOp::Mul => hir::BinOp::Mul,
1273 ast::BinOp::Neq => hir::BinOp::Neq,
1274 ast::BinOp::OrB => hir::BinOp::OrB,
1275 ast::BinOp::OrL => hir::BinOp::OrL,
1276 ast::BinOp::Shl => hir::BinOp::Shl,
1277 ast::BinOp::Shr => hir::BinOp::Shr,
1278 ast::BinOp::Sub => hir::BinOp::Sub,
1279 ast::BinOp::XorB => hir::BinOp::XorB,
1280 }
1281}
1282
1283fn lower_functor(functor: ast::Functor) -> hir::Functor {
1284 match functor {
1285 ast::Functor::Adj => hir::Functor::Adj,
1286 ast::Functor::Ctl => hir::Functor::Ctl,
1287 }
1288}
1289
1290fn is_partial_app(arg: &ast::Expr) -> bool {
1291 match arg.kind.as_ref() {
1292 ast::ExprKind::Hole => true,
1293 ast::ExprKind::Paren(inner) => is_partial_app(inner),
1294 ast::ExprKind::Tuple(items) => items.iter().any(|i| is_partial_app(i)),
1295 _ => false,
1296 }
1297}
1298