Skip to content

Commit 483d384

Browse files
committed
Fix scoping resolution for defs
1 parent dec185a commit 483d384

File tree

2 files changed

+174
-2
lines changed

2 files changed

+174
-2
lines changed

compiler/qsc_qasm3/src/semantic/symbols.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ impl SymbolTable {
447447
if let Some(scope) = last_false {
448448
if let Some((id, symbol)) = scope.get_symbol_by_name(name.as_ref()) {
449449
if symbol.ty.is_const()
450-
|| matches!(symbol.ty, Type::Gate(..) | Type::Void)
450+
|| matches!(symbol.ty, Type::Gate(..) | Type::Void | Type::Function(..))
451451
|| self.is_scope_rooted_in_global()
452452
{
453453
return Some((id, symbol));
@@ -457,7 +457,9 @@ impl SymbolTable {
457457
// we should be at the global, function, or gate scope now
458458
for scope in scopes {
459459
if let Some((id, symbol)) = scope.get_symbol_by_name(name.as_ref()) {
460-
if symbol.ty.is_const() || matches!(symbol.ty, Type::Gate(..) | Type::Void) {
460+
if symbol.ty.is_const()
461+
|| matches!(symbol.ty, Type::Gate(..) | Type::Void | Type::Function(..))
462+
{
461463
return Some((id, symbol));
462464
}
463465
}

compiler/qsc_qasm3/src/tests/scopes.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,173 @@ fn cannot_access_mutable_decls_from_global_scope() {
5454
};
5555
expect![r#"Undefined symbol: i."#].assert_eq(&errors[0].to_string());
5656
}
57+
58+
#[test]
59+
fn gates_can_call_previously_declared_gates() -> miette::Result<(), Vec<Report>> {
60+
let source = r#"
61+
include "stdgates.inc";
62+
gate my_h q {
63+
h q;
64+
}
65+
gate my_hx q {
66+
my_h q;
67+
x q;
68+
}
69+
qubit q;
70+
my_hx q;
71+
"#;
72+
73+
let qsharp = compile_qasm_to_qsharp(source)?;
74+
expect![[r#"
75+
import QasmStd.Angle.*;
76+
import QasmStd.Convert.*;
77+
import QasmStd.Intrinsic.*;
78+
let my_h : (Qubit) => Unit = (q) => {
79+
h(q);
80+
};
81+
let my_hx : (Qubit) => Unit = (q) => {
82+
my_h(q);
83+
x(q);
84+
};
85+
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
86+
my_hx(q);
87+
"#]]
88+
.assert_eq(&qsharp);
89+
Ok(())
90+
}
91+
92+
#[test]
93+
fn def_can_call_previously_declared_def() -> miette::Result<(), Vec<Report>> {
94+
let source = r#"
95+
include "stdgates.inc";
96+
def apply_h(qubit q) {
97+
h q;
98+
}
99+
def apply_hx(qubit q) {
100+
apply_h(q);
101+
x q;
102+
}
103+
qubit q;
104+
apply_hx(q);
105+
"#;
106+
107+
let qsharp = compile_qasm_to_qsharp(source)?;
108+
expect![[r#"
109+
import QasmStd.Angle.*;
110+
import QasmStd.Convert.*;
111+
import QasmStd.Intrinsic.*;
112+
let apply_h : (Qubit) => Unit = (q) => {
113+
h(q);
114+
};
115+
let apply_hx : (Qubit) => Unit = (q) => {
116+
apply_h(q);
117+
x(q);
118+
};
119+
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
120+
apply_hx(q);
121+
"#]]
122+
.assert_eq(&qsharp);
123+
Ok(())
124+
}
125+
126+
#[test]
127+
fn gate_can_call_previously_declared_def() -> miette::Result<(), Vec<Report>> {
128+
let source = r#"
129+
include "stdgates.inc";
130+
def apply_h(qubit q) {
131+
h q;
132+
}
133+
gate my_hx q {
134+
apply_h(q);
135+
x q;
136+
}
137+
qubit q;
138+
my_hx q;
139+
"#;
140+
141+
let qsharp = compile_qasm_to_qsharp(source)?;
142+
expect![[r#"
143+
import QasmStd.Angle.*;
144+
import QasmStd.Convert.*;
145+
import QasmStd.Intrinsic.*;
146+
let apply_h : (Qubit) => Unit = (q) => {
147+
h(q);
148+
};
149+
let my_hx : (Qubit) => Unit = (q) => {
150+
apply_h(q);
151+
x(q);
152+
};
153+
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
154+
my_hx(q);
155+
"#]]
156+
.assert_eq(&qsharp);
157+
Ok(())
158+
}
159+
160+
#[test]
161+
fn def_can_call_previously_declared_gate() -> miette::Result<(), Vec<Report>> {
162+
let source = r#"
163+
include "stdgates.inc";
164+
gate my_h q {
165+
h q;
166+
}
167+
def apply_hx(qubit q) {
168+
my_h q;
169+
x q;
170+
}
171+
qubit q;
172+
apply_hx(q);
173+
"#;
174+
175+
let qsharp = compile_qasm_to_qsharp(source)?;
176+
expect![[r#"
177+
import QasmStd.Angle.*;
178+
import QasmStd.Convert.*;
179+
import QasmStd.Intrinsic.*;
180+
let my_h : (Qubit) => Unit = (q) => {
181+
h(q);
182+
};
183+
let apply_hx : (Qubit) => Unit = (q) => {
184+
my_h(q);
185+
x(q);
186+
};
187+
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
188+
apply_hx(q);
189+
"#]]
190+
.assert_eq(&qsharp);
191+
Ok(())
192+
}
193+
194+
#[test]
195+
fn def_can_call_itself_recursively() -> miette::Result<(), Vec<Report>> {
196+
let source = r#"
197+
include "stdgates.inc";
198+
def apply_hx(int limit, qubit q) {
199+
if (limit > 0) {
200+
apply_hx(limit - 1, q);
201+
x q;
202+
}
203+
h q;
204+
}
205+
qubit q;
206+
apply_hx(2, q);
207+
"#;
208+
209+
let qsharp = compile_qasm_to_qsharp(source)?;
210+
expect![[r#"
211+
import QasmStd.Angle.*;
212+
import QasmStd.Convert.*;
213+
import QasmStd.Intrinsic.*;
214+
let apply_hx : (Int, Qubit) => Unit = (limit, q) => {
215+
if limit > 0 {
216+
apply_hx(limit - 1, q);
217+
x(q);
218+
};
219+
h(q);
220+
};
221+
let q = QIR.Runtime.__quantum__rt__qubit_allocate();
222+
apply_hx(2, q);
223+
"#]]
224+
.assert_eq(&qsharp);
225+
Ok(())
226+
}

0 commit comments

Comments
 (0)