Skip to content

Commit 7ebc428

Browse files
authored
Better feedback on incorrect syntax for qubit allocation (#2897)
This adds some additional help messages when code is known to be incorrectly performing qubit allocation. This addresses the remaining items from and fixes #331. <img width="708" height="214" alt="image" src="https://github.com/user-attachments/assets/b3d55bb0-9dd0-4235-b751-52f7ea204c89" /> <img width="708" height="214" alt="image" src="https://github.com/user-attachments/assets/033008ff-3023-4cd0-b916-1b6ce6e00872" />
1 parent 7db9f2d commit 7ebc428

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

source/compiler/qsc_frontend/src/resolve.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ pub(super) enum Error {
213213
#[diagnostic(code("Qsc.Resolve.NotFound"))]
214214
NotAvailable(String, String, #[label] Span),
215215

216+
#[error("`Qubit` not found")]
217+
#[diagnostic(help(
218+
"to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`"
219+
))]
220+
#[diagnostic(code("Qsc.Resolve.NotFoundQubit"))]
221+
NotFoundQubit(#[label] Span),
222+
216223
#[error("use of unimplemented item `{0}`")]
217224
#[diagnostic(help("this item is not implemented and cannot be used"))]
218225
#[diagnostic(code("Qsc.Resolve.Unimplemented"))]
@@ -772,6 +779,8 @@ impl Resolver {
772779
format!("{}.{}", dropped_name.namespace, dropped_name.name),
773780
span,
774781
))
782+
} else if name == "Qubit" {
783+
Err(Error::NotFoundQubit(span))
775784
} else {
776785
Err(Error::NotFound(name, span))
777786
}

source/compiler/qsc_frontend/src/resolve/tests.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,6 +2341,50 @@ fn resolve_local_generic() {
23412341
);
23422342
}
23432343

2344+
#[test]
2345+
fn incorrect_single_qubit_allocation_syntax_gets_extra_help() {
2346+
check(
2347+
indoc! {"
2348+
namespace A {
2349+
operation B() : Unit {
2350+
let q = Qubit();
2351+
}
2352+
}
2353+
"},
2354+
&expect![[r#"
2355+
namespace namespace3 {
2356+
operation package2_item1() : Unit {
2357+
let local13 = Qubit();
2358+
}
2359+
}
2360+
2361+
// NotFoundQubit(Span { lo: 57, hi: 62 })
2362+
"#]],
2363+
);
2364+
}
2365+
2366+
#[test]
2367+
fn incorrect_qubit_array_allocation_syntax_gets_extra_help() {
2368+
check(
2369+
indoc! {"
2370+
namespace A {
2371+
operation B() : Unit {
2372+
let q = Qubit[5];
2373+
}
2374+
}
2375+
"},
2376+
&expect![[r#"
2377+
namespace namespace3 {
2378+
operation package2_item1() : Unit {
2379+
let local13 = Qubit[5];
2380+
}
2381+
}
2382+
2383+
// NotFoundQubit(Span { lo: 57, hi: 62 })
2384+
"#]],
2385+
);
2386+
}
2387+
23442388
#[test]
23452389
fn dropped_base_callable_from_unrestricted() {
23462390
check_with_capabilities(

source/compiler/qsc_parse/src/stmt.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ fn parse_qubit(s: &mut ParserContext) -> Result<Box<StmtKind>> {
154154
}
155155

156156
fn parse_qubit_init(s: &mut ParserContext) -> Result<Box<QubitInit>> {
157+
let help_text = "to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`";
157158
let lo = s.peek().span.lo;
158159
s.expect(WordKinds::Qubit);
159160
let kind = if let Ok(name) = ident(s) {
@@ -162,33 +163,32 @@ fn parse_qubit_init(s: &mut ParserContext) -> Result<Box<QubitInit>> {
162163
"qubit initializer",
163164
"identifier",
164165
name.span,
165-
)));
166+
))
167+
.with_help(help_text));
166168
} else if token(s, TokenKind::Open(Delim::Paren)).is_ok() {
167-
token(s, TokenKind::Close(Delim::Paren))?;
169+
token(s, TokenKind::Close(Delim::Paren)).map_err(|e| e.with_help(help_text))?;
168170
QubitInitKind::Single
169171
} else if token(s, TokenKind::Open(Delim::Bracket)).is_ok() {
170-
let size = expr(s)?;
171-
token(s, TokenKind::Close(Delim::Bracket))?;
172+
let size = expr(s).map_err(|e| e.with_help(help_text))?;
173+
token(s, TokenKind::Close(Delim::Bracket)).map_err(|e| e.with_help(help_text))?;
172174
QubitInitKind::Array(size)
173175
} else {
174176
let token = s.peek();
175-
return Err(Error::new(ErrorKind::Rule(
176-
"qubit suffix",
177-
token.kind,
178-
token.span,
179-
)));
177+
return Err(
178+
Error::new(ErrorKind::Rule("qubit suffix", token.kind, token.span))
179+
.with_help(help_text),
180+
);
180181
}
181182
} else if token(s, TokenKind::Open(Delim::Paren)).is_ok() {
182-
let (inits, final_sep) = seq(s, parse_qubit_init)?;
183-
token(s, TokenKind::Close(Delim::Paren))?;
183+
let (inits, final_sep) = seq(s, parse_qubit_init).map_err(|e| e.with_help(help_text))?;
184+
token(s, TokenKind::Close(Delim::Paren)).map_err(|e| e.with_help(help_text))?;
184185
final_sep.reify(inits, QubitInitKind::Paren, QubitInitKind::Tuple)
185186
} else {
186187
let token = s.peek();
187-
return Err(Error::new(ErrorKind::Rule(
188-
"qubit initializer",
189-
token.kind,
190-
token.span,
191-
)));
188+
return Err(
189+
Error::new(ErrorKind::Rule("qubit initializer", token.kind, token.span))
190+
.with_help(help_text),
191+
);
192192
};
193193

194194
Ok(Box::new(QubitInit {

source/compiler/qsc_parse/src/stmt/tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ fn use_invalid_init() {
144144
hi: 14,
145145
},
146146
),
147+
Some(
148+
"to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`",
149+
),
147150
)
148151
"#]],
149152
);

0 commit comments

Comments
 (0)