Skip to content

Commit 4541053

Browse files
Remove Elided Pattern in HIR (microsoft#379)
1 parent 90a3e43 commit 4541053

File tree

36 files changed

+2674
-2395
lines changed

36 files changed

+2674
-2395
lines changed

compiler/qsc_eval/src/lib.rs

+35-17
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ use qir_backend::__quantum__rt__initialize;
2020
use qsc_data_structures::span::Span;
2121
use qsc_hir::hir::{
2222
self, BinOp, Block, CallableDecl, Expr, ExprKind, Field, Functor, Lit, LocalItemId, Mutability,
23-
NodeId, PackageId, Pat, PatKind, PrimField, Res, Spec, SpecBody, SpecGen, Stmt, StmtKind,
23+
NodeId, PackageId, Pat, PatKind, PrimField, Res, SpecBody, SpecGen, Stmt, StmtKind,
2424
StringComponent, TernOp, UnOp,
2525
};
2626
use std::{
2727
collections::{hash_map::Entry, HashMap},
2828
convert::AsRef,
29-
fmt::Write,
29+
fmt::{self, Display, Formatter, Write},
3030
iter,
3131
ops::Neg,
3232
ptr::null_mut,
@@ -56,7 +56,7 @@ pub enum Error {
5656
IntTooLarge(i64, #[label("this value is too large")] Span),
5757

5858
#[error("missing specialization: {0}")]
59-
MissingSpec(Spec, #[label("callable has no {0} specialization")] Span),
59+
MissingSpec(String, #[label("callable has no {0} specialization")] Span),
6060

6161
#[error("index out of range: {0}")]
6262
OutOfRange(i64, #[label("out of range")] Span),
@@ -86,6 +86,29 @@ pub enum Error {
8686
UserFail(String, #[label("explicit fail")] Span),
8787
}
8888

89+
/// A specialization that may be implemented for an operation.
90+
enum Spec {
91+
/// The default specialization.
92+
Body,
93+
/// The adjoint specialization.
94+
Adj,
95+
/// The controlled specialization.
96+
Ctl,
97+
/// The controlled adjoint specialization.
98+
CtlAdj,
99+
}
100+
101+
impl Display for Spec {
102+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
103+
match self {
104+
Spec::Body => f.write_str("body"),
105+
Spec::Adj => f.write_str("adjoint"),
106+
Spec::Ctl => f.write_str("controlled"),
107+
Spec::CtlAdj => f.write_str("controlled adjoint"),
108+
}
109+
}
110+
}
111+
89112
/// Evaluates the given statement with the given context.
90113
/// # Errors
91114
/// Returns the first error encountered during execution.
@@ -780,7 +803,7 @@ impl<'a, G: GlobalLookup<'a>> State<'a, G> {
780803
Spec::Ctl => callee.ctl.as_ref(),
781804
Spec::CtlAdj => callee.ctl_adj.as_ref(),
782805
}
783-
.ok_or(Error::MissingSpec(spec, callee_span))?
806+
.ok_or(Error::MissingSpec(spec.to_string(), callee_span))?
784807
.body;
785808
match block_body {
786809
SpecBody::Impl(input, body_block) => {
@@ -794,7 +817,7 @@ impl<'a, G: GlobalLookup<'a>> State<'a, G> {
794817
self.push_val(val);
795818
Ok(())
796819
}
797-
SpecBody::Gen(_) => Err(Error::MissingSpec(spec, callee_span)),
820+
SpecBody::Gen(_) => Err(Error::MissingSpec(spec.to_string(), callee_span)),
798821
}
799822
}
800823

@@ -990,7 +1013,6 @@ fn bind_value(env: &mut Env, pat: &Pat, val: Value, mutability: Mutability) {
9901013
};
9911014
}
9921015
PatKind::Discard => {}
993-
PatKind::Elided => panic!("elision used in binding"),
9941016
PatKind::Tuple(tup) => {
9951017
let val_tup = val.unwrap_tuple();
9961018
for (pat, val) in tup.iter().zip(val_tup.iter()) {
@@ -1038,17 +1060,12 @@ fn update_binding(env: &mut Env, lhs: &Expr, rhs: Value) -> Result<(), Error> {
10381060
fn bind_args_for_spec(
10391061
env: &mut Env,
10401062
decl_pat: &Pat,
1041-
spec_pat: &Pat,
1063+
spec_pat: &Option<Pat>,
10421064
args_val: Value,
10431065
ctl_count: u8,
10441066
) {
1045-
match &spec_pat.kind {
1046-
PatKind::Bind(_) | PatKind::Discard => {
1047-
panic!("spec pattern should be elided or elided tuple, found bind/discard")
1048-
}
1049-
PatKind::Elided => bind_value(env, decl_pat, args_val, Mutability::Immutable),
1050-
PatKind::Tuple(pats) => {
1051-
assert_eq!(pats.len(), 2, "spec pattern tuple should have 2 elements");
1067+
match spec_pat {
1068+
Some(spec_pat) => {
10521069
assert!(
10531070
ctl_count > 0,
10541071
"spec pattern tuple used without controlled functor"
@@ -1058,20 +1075,21 @@ fn bind_args_for_spec(
10581075
let mut ctls = vec![];
10591076
for _ in 0..ctl_count {
10601077
let [c, rest] = &*tup.unwrap_tuple() else {
1061-
panic!("tuple should be arity 2");
1062-
};
1078+
panic!("tuple should be arity 2");
1079+
};
10631080
ctls.extend_from_slice(&c.clone().unwrap_array());
10641081
tup = rest.clone();
10651082
}
10661083

10671084
bind_value(
10681085
env,
1069-
&pats[0],
1086+
spec_pat,
10701087
Value::Array(ctls.into()),
10711088
Mutability::Immutable,
10721089
);
10731090
bind_value(env, decl_pat, tup, Mutability::Immutable);
10741091
}
1092+
None => bind_value(env, decl_pat, args_val, Mutability::Immutable),
10751093
}
10761094
}
10771095

compiler/qsc_frontend/src/closure.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use qsc_hir::{
66
assigner::Assigner,
77
hir::{
88
Block, CallableDecl, CallableKind, Expr, ExprKind, Ident, Mutability, NodeId, Pat, PatKind,
9-
Res, Spec, SpecBody, SpecDecl, Stmt, StmtKind,
9+
Res, SpecBody, SpecDecl, Stmt, StmtKind,
1010
},
1111
mut_visit::{self, MutVisitor},
1212
ty::{Arrow, FunctorSetValue, Ty},
@@ -122,8 +122,6 @@ pub(super) fn lift(
122122
let mut input = closure_input(substituted_vars, lambda.input, span);
123123
assigner.visit_pat(&mut input);
124124

125-
let input_ty = input.ty.clone();
126-
127125
let callable = CallableDecl {
128126
id: assigner.next_node(),
129127
span,
@@ -140,14 +138,8 @@ pub(super) fn lift(
140138
body: SpecDecl {
141139
id: assigner.next_node(),
142140
span: lambda.body.span,
143-
spec: Spec::Body,
144141
body: SpecBody::Impl(
145-
Pat {
146-
id: assigner.next_node(),
147-
span,
148-
ty: input_ty,
149-
kind: PatKind::Elided,
150-
},
142+
None,
151143
Block {
152144
id: assigner.next_node(),
153145
span: lambda.body.span,

compiler/qsc_frontend/src/compile/tests.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ fn replace_node() {
293293
.kind else { panic!("item should be a callable"); };
294294
let SpecBody::Impl(_, block) = &callable.body.body else { panic!("callable body have a block") };
295295
expect![[r#"
296-
Block 5 [39-56] [Type Int]:
297-
Stmt 6 [49-50]: Expr: Expr 9 [49-50] [Type Int]: Lit: Int(2)"#]]
296+
Block 4 [39-56] [Type Int]:
297+
Stmt 5 [49-50]: Expr: Expr 8 [49-50] [Type Int]: Lit: Int(2)"#]]
298298
.assert_eq(&block.to_string());
299299
}
300300

@@ -365,20 +365,19 @@ fn insert_core_call() {
365365
expect![[r#"
366366
Package:
367367
Item 0 [0-43] (Public):
368-
Namespace (Ident 6 [10-11] "A"): Item 1
368+
Namespace (Ident 5 [10-11] "A"): Item 1
369369
Item 1 [18-41] (Public):
370370
Parent: 0
371371
Callable 0 [18-41] (operation):
372372
name: Ident 1 [28-31] "Foo"
373373
input: Pat 2 [31-33] [Type Unit]: Unit
374374
output: Unit
375375
functors: empty set
376-
body: SpecDecl 3 [18-41] (Body): Impl:
377-
Pat 4 [18-41] [Type Unit]: Elided
378-
Block 5 [39-41] [Type Unit]:
379-
Stmt 7 [0-0]: Semi: Expr 8 [0-0] [Type Qubit]: Call:
380-
Expr 9 [0-0] [Type (Unit => Qubit)]: Var: Item 4 (Package 0)
381-
Expr 10 [0-0] [Type Unit]: Unit
376+
body: SpecDecl 3 [18-41]: Impl:
377+
Block 4 [39-41] [Type Unit]:
378+
Stmt 6 [0-0]: Semi: Expr 7 [0-0] [Type Qubit]: Call:
379+
Expr 8 [0-0] [Type (Unit => Qubit)]: Var: Item 4 (Package 0)
380+
Expr 9 [0-0] [Type Unit]: Unit
382381
adj: <none>
383382
ctl: <none>
384383
ctl-adj: <none>"#]]

compiler/qsc_frontend/src/lower.rs

+28-19
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ pub(super) enum Error {
3232
MissingBody(#[label] Span),
3333
#[error("duplicate specialization")]
3434
DuplicateSpec(#[label] Span),
35+
#[error("invalid use of elided pattern")]
36+
InvalidElidedPat(#[label] Span),
37+
#[error("invalid pattern for specialization declaration")]
38+
InvalidSpecPat(#[label] Span),
3539
}
3640

3741
#[derive(Clone, Copy)]
@@ -222,16 +226,7 @@ impl With<'_> {
222226
let body = hir::SpecDecl {
223227
id: self.assigner.next_node(),
224228
span: decl.span,
225-
spec: hir::Spec::Body,
226-
body: hir::SpecBody::Impl(
227-
hir::Pat {
228-
id: self.assigner.next_node(),
229-
span: decl.span,
230-
ty: input.ty.clone(),
231-
kind: hir::PatKind::Elided,
232-
},
233-
self.lower_block(block),
234-
),
229+
body: hir::SpecBody::Impl(None, self.lower_block(block)),
235230
};
236231
(body, None, None, None)
237232
}
@@ -241,7 +236,6 @@ impl With<'_> {
241236
hir::SpecDecl {
242237
id: self.assigner.next_node(),
243238
span: decl.span,
244-
spec: hir::Spec::Body,
245239
body: hir::SpecBody::Gen(hir::SpecGen::Auto),
246240
}
247241
});
@@ -294,12 +288,6 @@ impl With<'_> {
294288
hir::SpecDecl {
295289
id: self.lower_id(decl.id),
296290
span: decl.span,
297-
spec: match decl.spec {
298-
ast::Spec::Body => hir::Spec::Body,
299-
ast::Spec::Adj => hir::Spec::Adj,
300-
ast::Spec::Ctl => hir::Spec::Ctl,
301-
ast::Spec::CtlAdj => hir::Spec::CtlAdj,
302-
},
303291
body: match &decl.body {
304292
ast::SpecBody::Gen(gen) => hir::SpecBody::Gen(match gen {
305293
ast::SpecGen::Auto => hir::SpecGen::Auto,
@@ -309,12 +297,30 @@ impl With<'_> {
309297
ast::SpecGen::Slf => hir::SpecGen::Slf,
310298
}),
311299
ast::SpecBody::Impl(input, block) => {
312-
hir::SpecBody::Impl(self.lower_pat(input), self.lower_block(block))
300+
hir::SpecBody::Impl(self.lower_spec_decl_pat(input), self.lower_block(block))
313301
}
314302
},
315303
}
316304
}
317305

306+
fn lower_spec_decl_pat(&mut self, pat: &ast::Pat) -> Option<hir::Pat> {
307+
if let ast::PatKind::Paren(inner) = &*pat.kind {
308+
return self.lower_spec_decl_pat(inner);
309+
}
310+
311+
match &*pat.kind {
312+
ast::PatKind::Elided => return None,
313+
ast::PatKind::Tuple(items)
314+
if items.len() == 2 && *items[1].kind == ast::PatKind::Elided =>
315+
{
316+
return Some(self.lower_pat(&items[0]));
317+
}
318+
_ => self.lowerer.errors.push(Error::InvalidSpecPat(pat.span)),
319+
};
320+
321+
None
322+
}
323+
318324
fn lower_block(&mut self, block: &ast::Block) -> hir::Block {
319325
hir::Block {
320326
id: self.lower_id(block.id),
@@ -621,7 +627,10 @@ impl With<'_> {
621627
hir::PatKind::Bind(name)
622628
}
623629
ast::PatKind::Discard(_) => hir::PatKind::Discard,
624-
ast::PatKind::Elided => hir::PatKind::Elided,
630+
ast::PatKind::Elided => {
631+
self.lowerer.errors.push(Error::InvalidElidedPat(pat.span));
632+
hir::PatKind::Discard
633+
}
625634
ast::PatKind::Paren(_) => unreachable!("parentheses should be removed earlier"),
626635
ast::PatKind::Tuple(items) => {
627636
hir::PatKind::Tuple(items.iter().map(|i| self.lower_pat(i)).collect())

0 commit comments

Comments
 (0)