diff --git a/source/compiler/qsc_frontend/src/resolve.rs b/source/compiler/qsc_frontend/src/resolve.rs index 72fffc96c4..7866470bf1 100644 --- a/source/compiler/qsc_frontend/src/resolve.rs +++ b/source/compiler/qsc_frontend/src/resolve.rs @@ -213,6 +213,13 @@ pub(super) enum Error { #[diagnostic(code("Qsc.Resolve.NotFound"))] NotAvailable(String, String, #[label] Span), + #[error("`Qubit` not found")] + #[diagnostic(help( + "to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`" + ))] + #[diagnostic(code("Qsc.Resolve.NotFoundQubit"))] + NotFoundQubit(#[label] Span), + #[error("use of unimplemented item `{0}`")] #[diagnostic(help("this item is not implemented and cannot be used"))] #[diagnostic(code("Qsc.Resolve.Unimplemented"))] @@ -772,6 +779,8 @@ impl Resolver { format!("{}.{}", dropped_name.namespace, dropped_name.name), span, )) + } else if name == "Qubit" { + Err(Error::NotFoundQubit(span)) } else { Err(Error::NotFound(name, span)) } diff --git a/source/compiler/qsc_frontend/src/resolve/tests.rs b/source/compiler/qsc_frontend/src/resolve/tests.rs index cc79c00817..5c24ff6803 100644 --- a/source/compiler/qsc_frontend/src/resolve/tests.rs +++ b/source/compiler/qsc_frontend/src/resolve/tests.rs @@ -2341,6 +2341,50 @@ fn resolve_local_generic() { ); } +#[test] +fn incorrect_single_qubit_allocation_syntax_gets_extra_help() { + check( + indoc! {" + namespace A { + operation B() : Unit { + let q = Qubit(); + } + } + "}, + &expect![[r#" + namespace namespace3 { + operation package2_item1() : Unit { + let local13 = Qubit(); + } + } + + // NotFoundQubit(Span { lo: 57, hi: 62 }) + "#]], + ); +} + +#[test] +fn incorrect_qubit_array_allocation_syntax_gets_extra_help() { + check( + indoc! {" + namespace A { + operation B() : Unit { + let q = Qubit[5]; + } + } + "}, + &expect![[r#" + namespace namespace3 { + operation package2_item1() : Unit { + let local13 = Qubit[5]; + } + } + + // NotFoundQubit(Span { lo: 57, hi: 62 }) + "#]], + ); +} + #[test] fn dropped_base_callable_from_unrestricted() { check_with_capabilities( diff --git a/source/compiler/qsc_parse/src/stmt.rs b/source/compiler/qsc_parse/src/stmt.rs index 2e40f13cae..974eb7d5fb 100644 --- a/source/compiler/qsc_parse/src/stmt.rs +++ b/source/compiler/qsc_parse/src/stmt.rs @@ -154,6 +154,7 @@ fn parse_qubit(s: &mut ParserContext) -> Result> { } fn parse_qubit_init(s: &mut ParserContext) -> Result> { + let help_text = "to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`"; let lo = s.peek().span.lo; s.expect(WordKinds::Qubit); let kind = if let Ok(name) = ident(s) { @@ -162,33 +163,32 @@ fn parse_qubit_init(s: &mut ParserContext) -> Result> { "qubit initializer", "identifier", name.span, - ))); + )) + .with_help(help_text)); } else if token(s, TokenKind::Open(Delim::Paren)).is_ok() { - token(s, TokenKind::Close(Delim::Paren))?; + token(s, TokenKind::Close(Delim::Paren)).map_err(|e| e.with_help(help_text))?; QubitInitKind::Single } else if token(s, TokenKind::Open(Delim::Bracket)).is_ok() { - let size = expr(s)?; - token(s, TokenKind::Close(Delim::Bracket))?; + let size = expr(s).map_err(|e| e.with_help(help_text))?; + token(s, TokenKind::Close(Delim::Bracket)).map_err(|e| e.with_help(help_text))?; QubitInitKind::Array(size) } else { let token = s.peek(); - return Err(Error::new(ErrorKind::Rule( - "qubit suffix", - token.kind, - token.span, - ))); + return Err( + Error::new(ErrorKind::Rule("qubit suffix", token.kind, token.span)) + .with_help(help_text), + ); } } else if token(s, TokenKind::Open(Delim::Paren)).is_ok() { - let (inits, final_sep) = seq(s, parse_qubit_init)?; - token(s, TokenKind::Close(Delim::Paren))?; + let (inits, final_sep) = seq(s, parse_qubit_init).map_err(|e| e.with_help(help_text))?; + token(s, TokenKind::Close(Delim::Paren)).map_err(|e| e.with_help(help_text))?; final_sep.reify(inits, QubitInitKind::Paren, QubitInitKind::Tuple) } else { let token = s.peek(); - return Err(Error::new(ErrorKind::Rule( - "qubit initializer", - token.kind, - token.span, - ))); + return Err( + Error::new(ErrorKind::Rule("qubit initializer", token.kind, token.span)) + .with_help(help_text), + ); }; Ok(Box::new(QubitInit { diff --git a/source/compiler/qsc_parse/src/stmt/tests.rs b/source/compiler/qsc_parse/src/stmt/tests.rs index 60d6eed67f..51d29981fc 100644 --- a/source/compiler/qsc_parse/src/stmt/tests.rs +++ b/source/compiler/qsc_parse/src/stmt/tests.rs @@ -144,6 +144,9 @@ fn use_invalid_init() { hi: 14, }, ), + Some( + "to allocate qubits, use syntax like `use q = Qubit();` or `use qs = Qubit[N];` or `use (q1, q2) = (Qubit(), Qubit());`", + ), ) "#]], );